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

C# 核心利器:委派與事件深度解析(下)

     編輯:關於C#

事件——建立在委派之上的發布/訂閱機制

1. 核心概念

事件是物件或類別在狀態變更時發出的通知。發出者稱「事件源」,處理者稱「接收者」。事件源不需知曉具體接收者,透過委派提供型別安全的封裝,實現鬆耦合協調。

事件四要素

  • 定義事件:public event EventHandler Click;
  • 激發事件:使用者點擊滑鼠
  • 監聽事件:button.Click += Button_Click;
  • 執行事件:void Button_Click(object sender, EventArgs e)

2. 打造完整事件機制的標準步驟

// 1. 定義委派型別
public delegate void ChangedEventHandler(object sender, EventArgs e);

// 2. 宣告事件
public event ChangedEventHandler Changed;

// 3. 受保護的激發方法(支援繼承覆寫)
protected virtual void OnChanged(EventArgs e) {
    Changed?.Invoke(this, e); // C# 6.0 null 條件運算子
}

// 4. 屬性設定時觸發
private string _text = string.Empty;
public string Text {
    get => _text;
    set {
        _text = value;
        OnChanged(EventArgs.Empty);
    }
}

訂閱與處理

var myText = new MyText();
myText.Changed += MyText_Changed; // 簡化語法

private static void MyText_Changed(object sender, EventArgs e) {
    Console.WriteLine($"Text 屬性已變更:{(sender as MyText).Text}");
}

3. 實戰案例:電子郵件轉發至傳真與手機

步驟一:自訂事件參數攜帶業務資料

public class MailMsgEventArgs : EventArgs {
    public readonly string From, To, Subject, Body;
    public MailMsgEventArgs(string from, string to, string subject, string body) {
        (From, To, Subject, Body) = (from, to, subject, body);
    }
}

步驟二:郵件管理器定義事件與模擬收信

public delegate void MailMsgEventHandler(object sender, MailMsgEventArgs e);

public class MailManager {
    public event MailMsgEventHandler MailMsg;

    protected virtual void OnMailMsg(MailMsgEventArgs e) {
        MailMsg?.Invoke(this, e);
    }

    public void SimulateArrivingMsg(string from, string to, string subject, string body) {
        OnMailMsg(new MailMsgEventArgs(from, to, subject, body));
    }
}

步驟三:傳真與手機類別訂閱事件

public class Fax {
    private readonly TextBox _log;
    public Fax(MailManager mgr, TextBox log) {
        _log = log;
        mgr.MailMsg += FaxMsg; // 訂閱
    }
    private void FaxMsg(object sender, MailMsgEventArgs e) {
        _log.AppendText($"[傳真] 從:{e.From} 至:{e.To} 主旨:{e.Subject}{Environment.NewLine}");
    }
    public void UnRegister(MailManager mgr) => mgr.MailMsg -= FaxMsg;
}

public class CallPhone {
    private readonly TextBox _log;
    public CallPhone(MailManager mgr, TextBox log) {
        _log = log;
        mgr.MailMsg += CellPhoneMsg;
    }
    private void CellPhoneMsg(object sender, MailMsgEventArgs e) {
        _log.AppendText($"[手機] 從:{e.From} 至:{e.To} 主旨:{e.Subject}{Environment.NewLine}");
    }
    public void UnRegister(MailManager mgr) => mgr.MailMsg -= CellPhoneMsg;
}

步驟四:WinForms 客戶端整合

public partial class Form1 : Form {
    private readonly MailManager _mgr = new();
    private readonly Fax _fax;
    private readonly CallPhone _phone;

    public Form1() {
        InitializeComponent();
        _fax = new Fax(_mgr, txtReceiver);
        _phone = new CallPhone(_mgr, txtReceiver);
    }

    private void btnSend_Click(object sender, EventArgs e) {
        _mgr.SimulateArrivingMsg(txtFrom.Text, txtTo.Text, txtSubject.Text, txtBody.Text);
    }
}

4. 事件的架構價值:鬆耦合

  • 無事件機制: MailManager 需直接 `new Fax()`、`new CallPhone()` 並呼叫其方法——強耦合、難擴充。
  • 有事件機制: MailManager 僅激發事件,完全不知 `Fax`/`CallPhone` 存在。新增 `SMS`、`Slack` 通道零修改 `MailManager`,完美符合開放/封鎖原則。

5. 進階補充

  • EventHandler<TEventArgs>:.NET 內建泛型委派,免自訂 `delegate`。
  • 自訂 add/remove 存取器: 可控制訂閱邏輯(如執行緒安全、弱事件模式)。
  • 弱事件模式: 避免事件源長期持有訂閱者導致記憶體洩漏(WPF `WeakEventManager`)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved