直接暴露委托字段存在風險:外部代碼可任意賦值(= 覆蓋)、直接調用 Invoke、清空調用列表。event 關鍵字將委托封裝為只能 +=/-=、只能在類內部觸發的受控成員。
public delegate int Calculate(int x, int y);public event Calculate OnCalculate;聲明上述事件後,編譯器生成:
private Calculate _onCalculate;add_OnCalculate 方法:內部調用 Delegate.Combineremove_OnCalculate 方法:內部調用 Delegate.Remove
// 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; }
}
}
| 特性 | 委托字段 | 事件 |
|---|---|---|
外部賦值 (=) | ✅ 允許(危險:覆蓋所有訂閱者) | ❌ 編譯錯誤 |
外部調用 Invoke | ✅ 允許(破壞封裝) | ❌ 編譯錯誤(僅類內可調用) |
| 外部 += / -= | ✅ 允許 | ✅ 允許(唯一合法操作) |
| 編譯器生成 | 單純字段 | 字段 + add/remove 存取器 |
| 線程安全 | 需手動鎖 | 存取器默認線程安全(Combine/Remove 原子) |
void EventHandler(object sender, TEventArgs e)public event EventHandler EventName; TEventArgs 繼承 EventArgs,攜帶上下文數據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 存取器,禁止外部直接調用/賦值,強制實現觀察者模式的「訂閱-通知」契約。理解其編譯器生成細節,能避免濫用委托字段導致的封裝破壞,編寫更健壯的事件驅動系統。