Menu
CoddyTech

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 started

Sự 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ẽ.

challenge icon

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ớp TemperatureMonitor trong không gian tên Monitoring, đó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ên TemperatureChanged, 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
    Nhớ dùng mẫu ?.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ột TemperatureMonitor và đăng ký hai hàm xử lý khác nhau với sự kiện TemperatureChanged củ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}
    Sau khi đăng ký cả hai hàm xử lý, hãy đặt nhiệt độ hai lần bằng các giá trị đầu vào. Mỗi lần bạn đặt nhiệt độ, cả hai hàm xử lý đều sẽ phản hồi.

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: 30

Lư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
    }
}
quiz iconTự kiểm tra

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

Tự luyện tập: Trình biên dịch C# online