Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C#

Cách đăng ký (subscribe) Event trong C# và có thể có nhiều subscriber cho một event không?

Khái niệm cơ bản

  • Event: Cơ chế cho phép class/đối tượng thông báo cho các class/đối tượng khác khi có sự kiện xảy ra.
  • Publisher (Người phát hành): Class raise event.
  • Subscriber (Người đăng ký): Class xử lý event.

Đặc điểm quan trọng

  • Có thể có nhiều subscriber cho một event.
  • Một subscriber có thể xử lý nhiều event từ nhiều publisher khác nhau.
  • Event không có subscriber sẽ không bao giờ được raise.
  • Publisher quyết định khi nào raise event; Subscriber quyết định hành động gì khi event xảy ra.

Ví dụ hoàn chỉnh: Video Encoder với nhiều Subscriber

using System;
using System.Threading;

// EventArgs tùy chỉnh
public class MP4 
{
    public string Title { get; set; }
}

public class MP4Args : EventArgs 
{
    public MP4 Video { get; set; }
}

// Publisher
public class MP4Encoder 
{
    // Định nghĩa event dùng EventHandler chuẩn
    public event EventHandler<MP4Args> VideoEncoded;

    public void Encode(MP4 video) 
    {
        Console.WriteLine("Đang encode video...");
        Thread.Sleep(1000); // Giả lập xử lý
        OnVideoEncoded(video);
    }

    protected virtual void OnVideoEncoded(MP4 video) 
    {
        VideoEncoded?.Invoke(this, new MP4Args { Video = video });
    }
}

// Subscriber 1: Gửi email
public class MailService 
{
    public void OnVideoEncoded(object sender, MP4Args e) 
    {
        Console.WriteLine($"[MailService] Gửi email cho video: {e.Video.Title}");
    }
}

// Subscriber 2: Gửi tin nhắn
public class MessageService 
{
    public void OnVideoEncoded(object sender, MP4Args e) 
    {
        Console.WriteLine($"[MessageService] Gửi tin nhắn cho video: {e.Video.Title}");
    }
}

// Subscriber 3: Log
public class LogService 
{
    public void OnVideoEncoded(object sender, MP4Args e) 
    {
        Console.WriteLine($"[LogService] Log: Video {e.Video.Title} đã encode xong lúc {DateTime.Now}");
    }
}

class Program 
{
    static void Main() 
    {
        var video = new MP4 { Title = "Eminem - Lose Yourself" };
        var encoder = new MP4Encoder();
        
        var mail = new MailService();
        var message = new MessageService();
        var log = new LogService();

        // Đăng ký nhiều subscriber cho cùng một event
        encoder.VideoEncoded += mail.OnVideoEncoded;
        encoder.VideoEncoded += message.OnVideoEncoded;
        encoder.VideoEncoded += log.OnVideoEncoded;

        encoder.Encode(video);
        
        Console.ReadKey();
    }
}

Kết quả chạy

Đang encode video...
[MailService] Gửi email cho video: Eminem - Lose Yourself
[MessageService] Gửi tin nhắn cho video: Eminem - Lose Yourself
[LogService] Log: Video Eminem - Lose Yourself đã encode xong lúc 2024-01-15 10:30:45

Best Practices

  • Luôn kiểm tra null trước khi invoke (dùng ?.Invoke từ C# 6).
  • Sử dụng EventHandler<TEventArgs> chuẩn thay vì delegate tùy chỉnh.
  • Hủy đăng ký (-=) khi không còn cần thiết để tránh memory leak.
  • Đánh dấu method raise event là protected virtual để cho phép override.