事件發布者
public class ChatServer {
// 1. 宣告委派型別
public delegate void MessageHandler(string message);
// 2. 宣告事件(基於委派)
public event MessageHandler OnSendMessage;
// 3. 觸發事件的方法
public void SendMessage() {
// 安全觸發:檢查是否有訂閱者
OnSendMessage?.Invoke("開始發送訊息!");
// 等同於:
// if (OnSendMessage != null) OnSendMessage("開始發送訊息!");
}
}
事件訂閱者
public class Form1 : Form {
private void TestCustomEvent() {
ChatServer server = new ChatServer();
// 訂閱事件:使用 += 運算子
server.OnSendMessage += Server_OnSendMessage;
// 觸發
server.SendMessage();
}
// 事件處理器:簽章必須符合委派
private void Server_OnSendMessage(string msg) {
Console.WriteLine($"[收到訊息] {msg}");
// 或更新 UI:this.Invoke(...)
}
// 取消訂閱(可選,防止記憶體洩漏)
private void Unsubscribe(ChatServer server) {
server.OnSendMessage -= Server_OnSendMessage;
}
}
進階模式
EventHandler 標準模式
public class ProgressReporter {
// 使用標準 EventHandler<TEventArgs>
public event EventHandler<ProgressEventArgs> ProgressChanged;
protected virtual void OnProgressChanged(ProgressEventArgs e) {
ProgressChanged?.Invoke(this, e);
}
public void DoWork() {
for (int i = 0; i <= 100; i += 10) {
OnProgressChanged(new ProgressEventArgs(i));
Thread.Sleep(100);
}
}
}
public class ProgressEventArgs : EventArgs {
public int Percent { get; }
public ProgressEventArgs(int percent) { Percent = percent; }
}
自訂事件存取器
public class CustomEventAccess {
private EventHandler<EventArgs> handlers;
public event EventHandler<EventArgs> CustomEvent {
add {
lock (this) { handlers += value; }
Console.WriteLine("訂閱者加入");
}
remove {
lock (this) { handlers -= value; }
Console.WriteLine("訂閱者移除");
}
}
protected void Raise() {
handlers?.Invoke(this, EventArgs.Empty);
}
}
關鍵最佳實務
- null 條件運算子:
Event?.Invoke(args) 取代 if (Event != null),執行緒安全
- 虛擬觸發方法:
protected virtual void OnXxx() 允許衍生類別擴充
- EventArgs 衍生:傳遞豐富資料,遵循 .NET 命名慣例
- 取消訂閱:
IDisposable 模式或明確 -=,防止記憶體洩漏
- 執行緒安全:事件欄位本身非執行緒安全,高併發場景考慮
lock 或 Interlocked