Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Delegates, Events & Lambda

Delegates

// Delegate declaration
public delegate void Notify(string message);

// Delegate instance
Notify notifier = SendEmail;

// Multicast delegate
notifier += SendSMS;
notifier += LogMessage;

// Invoke
notifier("Hello!");

// Built-in delegates
Action<string> action = Console.WriteLine;
Func<int, int, int> add = (a, b) => a + b;
Predicate<int> isEven = n => n % 2 == 0;

void SendEmail(string msg) { /* ... */ }
void SendSMS(string msg) { /* ... */ }
void LogMessage(string msg) { /* ... */ }

Events

public class Button
{
    // Event declaration
    public event EventHandler Clicked;
    
    public void Click()
    {
        // Raise event
        Clicked?.Invoke(this, EventArgs.Empty);
    }
}

// Sử dụng
var button = new Button();
button.Clicked += (sender, e) => Console.WriteLine("Button clicked!");

// Event với custom EventArgs
public class OrderPlacedEventArgs : EventArgs
{
    public int OrderId { get; set; }
    public decimal Total { get; set; }
}

public class OrderService
{
    public event EventHandler<OrderPlacedEventArgs> OrderPlaced;
    
    public void PlaceOrder(Order order)
    {
        // Process order
        OrderPlaced?.Invoke(this, new OrderPlacedEventArgs
        {
            OrderId = order.Id,
            Total = order.Total
        });
    }
}

Lambda Expressions

// Expression lambda
Func<int, int> square = x => x * x;

// Statement lambda
Action<int> print = x =>
{
    Console.WriteLine($"Value: {x}");
    Console.WriteLine($"Square: {x * x}");
};

// Lambda với multiple parameters
Func<int, int, int> multiply = (x, y) => x * y;

// Sử dụng trong LINQ
var evenNumbers = numbers.Where(n => n % 2 == 0);

Mối quan hệ giữa Delegate, Event và Lambda Expression

Ba khái niệm này có mối quan hệ chặt chẽ và thường bị nhầm lẫn. Hiểu được bản chất của chúng sẽ giúp bạn sử dụng đúng cách.

Bản chất

Khái niệmBản chấtVai trò
DelegateKiểu dữ liệu (type-safe function pointer)Định nghĩa “hợp đồng” cho phương thức
Lambda ExpressionCú pháp (syntax)Cách viết ngắn gọn cho anonymous method
EventCơ chế bảo vệ (wrapper)Giới hạn truy cập delegate, chỉ cho phép +=-=

Mối quan hệ

┌─────────────────────────────────────────────────────────────┐
│                     Mối quan hệ                              │
│                                                             │
│   Lambda Expression ──► tạo ra ──► Delegate Instance         │
│                              │                              │
│                              ▼                              │
│   Event ──► bao bọc (wraps) ──► Delegate Field              │
│                                                             │
│   Kết quả: Event + Lambda = Pattern phổ biến trong C#       │
└─────────────────────────────────────────────────────────────┘

Giải thích chi tiết

1. Lambda Expression thực chất là Delegate

Khi bạn viết một lambda expression, compiler sẽ chuyển nó thành delegate:

// Lambda expression
Func<int, int> square = x => x * x;

// Compiler tạo ra tương đương:
Func<int, int> square = delegate(int x) { return x * x; };

// Hoặc thậm chí là một phương thức private:
// private static int <Main>b__0_0(int x) { return x * x; }

2. Event là “wrapper” bảo vệ cho Delegate

Event không phải là một kiểu riêng biệt - nó là một delegate được bảo vệ:

public class Publisher
{
    // Delegate field (private)
    private EventHandler _clicked;
    
    // Event - chỉ cho phép += và -= từ bên ngoài
    public event EventHandler Clicked
    {
        add { _clicked += value; }
        remove { _clicked -= value; }
    }
    
    // Bên trong class, có thể Invoke
    public void Raise() => _clicked?.Invoke(this, EventArgs.Empty);
}

3. Lambda + Event = Pattern phổ biến

// Lambda expression được dùng để tạo delegate handler
button.Clicked += (sender, e) => Console.WriteLine("Clicked!");
//                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                Lambda expression → EventHandler delegate

Ví dụ tổng hợp

// 1. Định nghĩa delegate (kiểu)
public delegate void MessageHandler(string message);

public class ChatRoom
{
    // 2. Event bao bọc delegate
    public event MessageHandler MessageReceived;
    
    public void SendMessage(string from, string message)
    {
        // 3. Lambda expression tạo delegate instance để invoke
        MessageReceived?.Invoke($"{from}: {message}");
    }
}

// 4. Sử dụng lambda để subscribe event
var chat = new ChatRoom();
chat.MessageReceived += msg => Console.WriteLine(msg);
//                           ^^^^^^^^^^^^^^^^^^^^^^^^^^
//                           Lambda → MessageHandler delegate

chat.SendMessage("Alice", "Hello!");

Khi nào dùng gì?

Tình huốngSử dụng
Truyền method như parameterFunc<>, Action<>, hoặc custom delegate
LINQ queriesLambda expression
Callback không cần exposeLambda → Delegate
Publisher-Subscriber patternEvent
Cần giới hạn truy cập (chỉ +=/-=)Event
Cần Invoke từ bên ngoàiDelegate (không dùng event)

Lưu ý quan trọng

  1. Event không thể Invoke từ bên ngoài class - Đây là sự khác biệt chính so với delegate
  2. Lambda expression không có kiểu riêng - Nó phải được gán cho một delegate type
  3. Event tự động generate add/remove - Tương tự property tự động generate getter/setter