Delegate và sự kiện
Thuộc phần Lập trình hướng đối tượng trong hành trình C# của Coddy. Bài học 43 trên 70.
Delegate là một kiểu dữ liệu đại diện cho tham chiếu đến một phương thức. Hãy hình dung nó như một biến chứa phương thức thay vì dữ liệu. Nhờ vậy, bạn có thể truyền phương thức làm đối số, lưu trữ chúng trong các tập hợp và gọi chúng một cách linh hoạt.
Bạn khai báo một delegate bằng cách chỉ định chữ ký phương thức mà nó có thể tham chiếu:
public delegate void Notify(string message);
public class Publisher
{
public void SendAlert(string msg) => Console.WriteLine("Alert: " + msg);
}
// Cách dùng
Notify notifier = new Publisher().SendAlert;
notifier("System started"); // Alert: System startedSự kiện phát triển dựa trên delegate để triển khai mẫu publish-subscribe. Một lớp phát ra sự kiện, các lớp khác có thể đăng ký để nhận thông báo. Từ khóa event hạn chế cách sử dụng delegate: bên đăng ký chỉ có thể thêm hoặc xóa trình xử lý, không thể gọi trực tiếp sự kiện.
public class Button
{
public event Action Clicked;
public void Click()
{
Clicked?.Invoke(); // Thông báo cho tất cả bên đăng ký
}
}
// Đăng ký nhận sự kiện
Button btn = new Button();
btn.Clicked += () => Console.WriteLine("Button was clicked!");
btn.Click(); // Đã nhấp vào nút!Toán tử += đăng ký một trình xử lý, còn -= hủy đăng ký. Mẫu ?.Invoke() gọi sự kiện một cách an toàn chỉ khi có người đăng ký. Sự kiện là thành phần nền tảng trong các ứng dụng GUI, game engine và mọi hệ thống mà các đối tượng cần phản ứng với thay đổi mà không bị liên kết chặt chẽ.
Thử thách
DễHãy xây dựng một hệ thống theo dõi nhiệt độ sử dụng delegate và sự kiện (event) để thông báo cho các bên đăng ký mỗi khi nhiệt độ thay đổi. Đây là ví dụ kinh điển về mẫu xuất bản và đăng ký, được sự kiện hỗ trợ một cách tinh tế.
Bạn sẽ sắp xếp code trong hai tệp:
TemperatureMonitor.cs: Tạo lớpTemperatureMonitortrong không gian tênMonitoring, đóng vai trò là bên phát. Bộ theo dõi của bạn cần:- Có một trường riêng để lưu nhiệt độ hiện tại
- Khai báo một sự kiện dùng
Action<int>có tênTemperatureChanged, sự kiện này được kích hoạt mỗi khi nhiệt độ được cập nhật - Có thuộc tính
Temperature(int), trong đó hàm setter cập nhật trường riêng và kích hoạt sự kiện với giá trị nhiệt độ mới
?.Invoke()để chỉ kích hoạt sự kiện một cách an toàn khi có bên đăng ký.Program.cs: Trong tệp chính, hãy tạo mộtTemperatureMonitorvà đăng ký hai hàm xử lý khác nhau với sự kiệnTemperatureChangedcủa nó:- Một hàm xử lý in ra:
Alert: Temperature is now {value} degrees - Một hàm xử lý khác in ra:
Logged: {value}
- Một hàm xử lý in ra:
Bạn sẽ nhận hai giá trị đầu vào:
- Giá trị nhiệt độ thứ nhất (số nguyên)
- Giá trị nhiệt độ thứ hai (số nguyên)
Ví dụ, nếu đầu vào là 25 và 30, đầu ra sẽ là:
Alert: Temperature is now 25 degrees
Logged: 25
Alert: Temperature is now 30 degrees
Logged: 30Lưu ý cách đặt thuộc tính Temperature tự động thông báo cho tất cả bên đăng ký, bộ theo dõi không cần biết ai đang lắng nghe. Đó chính là điểm hay của cách tiếp cận hướng sự kiện!
Tự làm thử
using System;
using Monitoring;
class Program
{
public static void Main(string[] args)
{
// Đọc đầu vào
int temp1 = Convert.ToInt32(Console.ReadLine());
int temp2 = Convert.ToInt32(Console.ReadLine());
// TODO: Tạo một instance TemperatureMonitor
// TODO: Đăng ký một hàm xử lý in ra: "Alert: Temperature is now {value} degrees"
// TODO: Đăng ký một hàm xử lý khác in ra: "Logged: {value}"
// TODO: Đặt nhiệt độ thành temp1
// TODO: Đặt nhiệt độ thành temp2
}
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Các khái niệm cơ bản về lập trình hướng đối tượng
Tệp bên ngoàiKhông gian tên và chỉ thịGiới thiệu về lớp và đối tượngTừ khóa thisPhương thức và tham sốTrường và thuộc tínhHàm khởi tạoKhởi tạo đối tượngÔn tập: Máy tính đơn giản4Kế thừa
Cú pháp kế thừa cơ bản (:)Từ khóa 'base'Từ khóa virtual và overrideLớp sealedLớp cơ sở 'object'Ôn tập: hệ phân cấp nhân viên7Tính năng nâng cao
Nạp chồng toán tửBộ lập chỉ mục (this[])Ghi đè ToString()Phương thức mở rộngÔn tập: Danh sách tùy chỉnh10Các mẫu thiết kế phần 1
Giới thiệu về mẫu thiết kếSingleton an toàn với luồngMẫu FactoryMẫu Observer (sự kiện)Mẫu Strategy2Thuộc tính và thành viên tĩnh
Thuộc tính tự độngThuộc tính chỉ đọc hoặc chỉ ghiTrường và phương thức tĩnhLớp tĩnhThành viên có thân biểu thức5Đa hình và interface
Đa hình lúc biên dịch và lúc chạyInterface và lớp trừu tượngNhiều interfaceInterface tường minhUpcasting và downcastingÔn tập: bộ tính toán hình học8Các khái niệm OOP nâng cao
Ưu tiên composition hơn kế thừaGenerics (lớp và phương thức)Delegate và sự kiệnAttribute và reflectionGiao diện IDisposable và câu lệnh usingKiến thức cơ bản về dependency injection11Các mẫu thiết kế phần 2
Mẫu lệnhMẫu bộ chuyển đổiMẫu trang tríMẫu phương thức khuôn mẫuMẫu trạng tháiMẫu tổ hợpTự luyện tập: Trình biên dịch C# online