首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 委託與事件深度解析:從原理到異步解耦實戰

     編輯:關於C語言

核心概念

  • 委託:類型安全的方法引用,類似 C++ 函數指針但支援實例方法、多播、受控執行
  • 事件:基於特定簽名委託的發布/訂閱機制,實現鬆耦合通知

委託三步走


// 1. 聲明委託類型(簽名)
public delegate void MyDelegate(string name);

// 2. 目標方法(匹配簽名)
public static void MyDelegateFunc(string name)
{
    Console.WriteLine("Hello, {0}", name);
}

// 3. 實例化並調用
MyDelegate md = new MyDelegate(MyDelegateFunc);
md("sam1111"); // 輸出: Hello, sam1111

事件標準模式


// 1. 事件參數類(可選,無參數用 EventArgs)
public class MyEventArgs : EventArgs
{
    public string Message { get; set; }
}

// 2. 事件處理器委託
public delegate void MyEventHandler(object sender, MyEventArgs e);

// 3. 發布者類
public class Publisher
{
    public event MyEventHandler MyEvent;

    protected virtual void OnMyEvent(MyEventArgs e)
    {
        MyEvent?.Invoke(this, e); // C# 6+ null 條件調用
    }

    public void DoWork()
    {
        // ... 業務邏輯 ...
        OnMyEvent(new MyEventArgs { Message = "Completed" });
    }
}

// 4. 訂閱者
public class Subscriber
{
    public void Subscribe(Publisher pub)
    {
        pub.MyEvent += HandleEvent;
    }

    private void HandleEvent(object sender, MyEventArgs e)
    {
        Console.WriteLine($"Received: {e.Message}");
    }
}

實戰場景:耗時任務進度回報

UI 執行緒啟動工作執行緒,通過事件回報進度:


public class TaskWorker
{
    public event EventHandler ProgressChanged;
    public event EventHandler Completed;

    public void Start()
    {
        Task.Run(() =>
        {
            for (int i = 0; i <= 100; i += 10)
            {
                Thread.Sleep(100); // 模擬工作
                ProgressChanged?.Invoke(this, new ProgressEventArgs(i));
            }
            Completed?.Invoke(this, new CompletedEventArgs(true));
        });
    }
}

// UI 端
var worker = new TaskWorker();
worker.ProgressChanged += (s, e) => progressBar.Value = e.Percent;
worker.Completed += (s, e) => MessageBox.Show("Done!");
worker.Start();

反模式與正確做法

反模式問題正確做法
子窗口持有父窗口引用直接調用方法雙向耦合,難維護、難測試子窗口觸發事件,父窗口訂閱處理
事件處理器簽名不匹配編譯錯誤或運行時異常嚴格遵循 (object sender, EventArgs e)
忘記取消訂閱 (-=)內存洩漏、重複執行在 Dispose/Unload 中取消訂閱

進階主題

  • 泛型委託:Action<T>、Func<T, TResult> 減少自定義委託聲明
  • 異步模式:BeginInvoke/EndInvoke 或 Task 結合事件
  • 弱事件模式:解決訂閱者生命週期長於發布者的內存洩漏
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved