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ệm | Bản chất | Vai trò |
|---|---|---|
| Delegate | Kiểu dữ liệu (type-safe function pointer) | Định nghĩa “hợp đồng” cho phương thức |
| Lambda Expression | Cú pháp (syntax) | Cách viết ngắn gọn cho anonymous method |
| Event | Cơ chế bảo vệ (wrapper) | Giới hạn truy cập delegate, chỉ cho phép += và -= |
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ống | Sử dụng |
|---|---|
| Truyền method như parameter | Func<>, Action<>, hoặc custom delegate |
| LINQ queries | Lambda expression |
| Callback không cần expose | Lambda → Delegate |
| Publisher-Subscriber pattern | Event |
| Cần giới hạn truy cập (chỉ +=/-=) | Event |
| Cần Invoke từ bên ngoài | Delegate (không dùng event) |
Lưu ý quan trọng
- Event không thể Invoke từ bên ngoài class - Đây là sự khác biệt chính so với delegate
- Lambda expression không có kiểu riêng - Nó phải được gán cho một delegate type
- Event tự động generate add/remove - Tương tự property tự động generate getter/setter