在現代軟體開發中,物件之間的通訊至關重要。C# 的事件機制實作了經典的發布/訂閱模式,讓物件能夠在不需要知道具體接收者的情況下發送通知。這種鬆耦合的設計讓程式碼更具彈性、可維護性與擴展性。
EventArgs)委派是事件機制的基石,它是一種型別安全的函式指標。與 C/C++ 的函式指標不同,委派具有:
event 關鍵字基於委派建立事件+= / -= 運算子管理事件清單以下範例改編自《C# 入門經典》,展示一個模擬連線監聽的場景:
using System;
using System.Timers;
namespace EventDemo
{
// 步驟 1:定義委派型別
public delegate void MessageHandler(string messageText);
public class Connection
{
// 步驟 2:宣告事件
public event MessageHandler MessageArrived;
private Timer _pollTimer;
public Connection()
{
_pollTimer = new Timer(100);
_pollTimer.Elapsed += CheckForMessage;
}
public void Connect() => _pollTimer.Start();
public void Disconnect() => _pollTimer.Stop();
private void CheckForMessage(object sender, ElapsedEventArgs e)
{
Console.WriteLine("正在檢查訊息...");
var random = new Random();
// 模擬 10% 機率收到訊息
if (random.Next(9) == 0 && MessageArrived != null)
{
// 步驟 5:引發事件(通知所有訂閱者)
MessageArrived("Hello Mum!");
}
}
}
}
namespace EventDemo
{
public class Display
{
// 步驟 3:實作事件處理方法(簽名需符合 MessageHandler)
public void DisplayMessage(string message)
{
Console.WriteLine($"[收到訊息] {message}");
}
}
}
namespace EventDemo
{
class Program
{
static void Main(string[] args)
{
var connection = new Connection();
var display = new Display();
// 步驟 4 & 5:訂閱事件
connection.MessageArrived += new MessageHandler(display.DisplayMessage);
connection.Connect();
Console.WriteLine("連線已啟動,按 Enter 鍵結束...");
Console.ReadLine();
// 良好習慣:取消訂閱防止記憶體洩漏
connection.MessageArrived -= new MessageHandler(display.DisplayMessage);
}
}
}
MessageArrived != null?事件在沒有任何訂閱者時為 null。直接呼叫會拋出 NullReferenceException。這是事件與委派的重要差異之一——事件提供了封裝保護,只能在類別內部引發。
event 關鍵字的意義+=/-=),不能直接指派(=)或引發事件從 C# 2.0 起,支援匿名方法;C# 3.0 引入 Lambda 運算式,讓訂閱更簡潔:
// 使用 Lambda 運算式直接訂閱
connection.MessageArrived += msg => Console.WriteLine($"Lambda 接收: {msg}");
// 使用方法群組轉換(C# 2.0+)
connection.MessageArrived += display.DisplayMessage;
.NET Framework 建議遵循標準模式:
// 1. 自訂 EventArgs 攜帶資料
public class MessageEventArgs : EventArgs
{
public string Content { get; }
public DateTime Timestamp { get; }
public MessageEventArgs(string content)
{
Content = content;
Timestamp = DateTime.Now;
}
}
// 2. 使用 EventHandler
public event EventHandler MessageReceived;
// 3. 引發事件的保護虛擬方法(支援繼承類別覆寫)
protected virtual void OnMessageReceived(MessageEventArgs e)
{
MessageReceived?.Invoke(this, e); // C# 6.0 Null 條件運算子
}
Dispose、表單關閉)取消訂閱多執行緒環境下,建議使用區域變數快取事件委派:
protected virtual void OnMessageReceived(MessageEventArgs e)
{
// 避免檢查與呼叫之間有訂閱者異動
var handler = MessageReceived;
handler?.Invoke(this, e);
}
C# 事件機制建立在委派之上,透過 event 關鍵字提供封裝保護,實現了鬆耦合的發布/訂閱模式。掌握「定義委派 → 宣告事件 → 引發事件 → 訂閱處理」的完整流程,並理解 null 檢查、記憶體管理、執行緒安全等實務細節,是編寫健壯 C# 應用程式的核心功力。