事件是物件或類別在狀態變更時發出的通知。發出者稱「事件源」,處理者稱「接收者」。事件源不需知曉具體接收者,透過委派提供型別安全的封裝,實現鬆耦合協調。
public event EventHandler Click;button.Click += Button_Click;void Button_Click(object sender, EventArgs e)// 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}");
}
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;
}
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);
}
}
MailManager 需直接 `new Fax()`、`new CallPhone()` 並呼叫其方法——強耦合、難擴充。MailManager 僅激發事件,完全不知 `Fax`/`CallPhone` 存在。新增 `SMS`、`Slack` 通道零修改 `MailManager`,完美符合開放/封鎖原則。