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

C# 事件機制深度解析:從委托到事件的編譯器魔法

     編輯:關於C語言

事件的由來:委托的「受控封裝」

直接暴露委托字段存在風險:外部代碼可任意賦值(= 覆蓋)、直接調用 Invoke、清空調用列表。event 關鍵字將委托封裝為只能 +=/-=、只能在類內部觸發的受控成員。

聲明事件的兩步驟

  1. 定義委托類型:public delegate int Calculate(int x, int y);
  2. 聲明事件:public event Calculate OnCalculate;

編譯器生成的內部結構(ILDASM 視角)

聲明上述事件後,編譯器生成:

  • 私有委托字段:private Calculate _onCalculate;
  • add_OnCalculate 方法:內部調用 Delegate.Combine
  • remove_OnCalculate 方法:內部調用 Delegate.Remove

IL 片段解讀


// add_OnCalculate 核心 IL
IL_0008: call class [mscorlib]System.Delegate 
    [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, 
    class [mscorlib]System.Delegate)

// remove_OnCalculate 核心 IL
call class [mscorlib]System.Delegate 
    [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate, 
    class [mscorlib]System.Delegate)

結論:event 純屬語法糖,本質是受控的委托存取器,無運行期額外開銷。

完整案例:汽車事件系統(補充版)


public class EventCar
{
    // 委托與事件
    public delegate void CarEventHandler(string msg);
    public event CarEventHandler AbortToBlow;
    public event CarEventHandler Exploded;
    
    // 狀態
    private const int MaxSpeed = 180;
    public int CurrSpeed { get; private set; }
    public bool IsDead { get; private set; }
    public string Name { get; private set; }
    
    // 構造
    public EventCar() { }
    public EventCar(string carName, int currSpeed)
    {
        if (currSpeed > MaxSpeed) IsDead = true;
        else { Name = carName; CurrSpeed = currSpeed; }
    }
}

事件 vs 委托:核心差異表

特性委托字段事件
外部賦值 (=)✅ 允許(危險:覆蓋所有訂閱者)❌ 編譯錯誤
外部調用 Invoke✅ 允許(破壞封裝)❌ 編譯錯誤(僅類內可調用)
外部 += / -=✅ 允許✅ 允許(唯一合法操作)
編譯器生成單純字段字段 + add/remove 存取器
線程安全需手動鎖存取器默認線程安全(Combine/Remove 原子)

標準 .NET 事件模式(生產代碼規範)

  1. 委托簽名:void EventHandler(object sender, TEventArgs e)
  2. 事件聲明:public event EventHandler EventName;
  3. TEventArgs 繼承 EventArgs,攜帶上下文數據
  4. 觸發方法:protected virtual void OnEventName(TEventArgs e) => EventName?.Invoke(this, e);

// 標準模式實現
public class CarEventArgs : EventArgs 
{ 
    public string Message { get; }
    public int Speed { get; }
    public CarEventArgs(string msg, int speed) { Message = msg; Speed = speed; }
}

public class StandardCar
{
    public event EventHandler SpeedWarning;
    public event EventHandler CarExploded;
    
    protected virtual void OnSpeedWarning(CarEventArgs e) 
        => SpeedWarning?.Invoke(this, e);
    
    protected virtual void OnCarExploded(CarEventArgs e) 
        => CarExploded?.Invoke(this, e);
    
    // 業務邏輯中調用 OnXxx 而非直接 Invoke
}

總結

event 關鍵字是 C# 對委托的語法級封裝:編譯器自動生成線程安全的 add/remove 存取器,禁止外部直接調用/賦值,強制實現觀察者模式的「訂閱-通知」契約。理解其編譯器生成細節,能避免濫用委托字段導致的封裝破壞,編寫更健壯的事件驅動系統。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved