C#作為.NET開發(fā)的核心語言之一,提供了豐富的特性來支持面向?qū)ο缶幊毯褪录?qū)動的模型。其中,委托和事件是C#中不可或缺的關(guān)鍵概念,每個(gè).NET開發(fā)者都應(yīng)該深入理解它們的作用和用法。委托和事件密不可分,所以本文將委托和事件的知識點(diǎn)一起介紹,并通過一些示例來幫助開發(fā)者更好地掌握這些重要的概念。
一、委托
委托讓方法引用的靈活利用
1、委托的定義與使用
委托是一種數(shù)據(jù)類型,用于持有對一個(gè)或多個(gè)方法的引用。通過委托,你可以將方法作為參數(shù)傳遞給其他方法,實(shí)現(xiàn)回調(diào)機(jī)制,實(shí)現(xiàn)方法的動態(tài)調(diào)用。使用`delegate`關(guān)鍵字可以聲明委托類型,并創(chuàng)建委托實(shí)例來綁定具體方法。
using System;//定義一個(gè)委托delegate int CalculatorDelegate(int a, int b);class Calculator{ public int Add(int a, int b) { return a + b; } public int Subtract(int a, int b) { return a - b; }}class Program{ static void Main(string[] args) { Calculator calculator = new Calculator(); // 聲明委托實(shí)例,并綁定到 Add 方法 CalculatorDelegate funDelegate = new CalculatorDelegate(calculator.Add); // 使用委托調(diào)用方法 int result = funDelegate (5, 2); Console.WriteLine($"5 + 2 = {result}"); // 將委托重新綁定到 Subtract 方法 funDelegate = calculator.Subtract; // 使用委托調(diào)用不同的方法 result = funDelegate(8, 6); Console.WriteLine($"8 - 6 = {result}"); }}
使用try.dot.net的測試結(jié)果:
?
2、委托的多播
委托不僅可以持有單個(gè)方法的引用,還可以用于多播,即將多個(gè)方法綁定到同一個(gè)委托實(shí)例。多播委托允許按順序調(diào)用這些方法,實(shí)現(xiàn)一次觸發(fā)多個(gè)方法的功能。
using System;delegate void MyDelegate(); // 定義委托class EventPublisher{ private MyDelegate eventHandlers; // 多播委托實(shí)例 public void AddHandler(MyDelegate handler) { eventHandlers += handler; // 添加委托方法到多播鏈 } public void RemoveHandler(MyDelegate handler) { eventHandlers -= handler; // 從多播鏈中移除委托方法 } public void RaiseEvent() { Console.WriteLine("事件發(fā)布者正在引發(fā)事件..."); eventHandlers?.Invoke(); // 調(diào)用多播鏈中的委托方法 }}class Program{ static void Main(string[] args) { EventPublisher publisher = new EventPublisher(); // 添加多個(gè)事件處理程序到多播鏈 publisher.AddHandler(Method1); publisher.AddHandler(Method2); publisher.AddHandler(Method3); // 觸發(fā)事件,調(diào)用多播鏈中的所有方法 publisher.RaiseEvent(); // 移除一個(gè)事件處理程序 publisher.RemoveHandler(Method2); // 再次觸發(fā)事件 publisher.RaiseEvent(); Console.ReadKey(); } static void Method1() { Console.WriteLine("方法1運(yùn)行."); } static void Method2() { Console.WriteLine("方法2運(yùn)行."); } static void Method3() { Console.WriteLine("方法3運(yùn)行."); }}
輸出結(jié)果:

3、 匿名方法與Lambda表達(dá)式
C# 2.0 引入了匿名方法,允許在沒有顯示聲明方法的情況下傳遞代碼塊作為委托參數(shù)。而Lambda表達(dá)式則是C# 3.0 的新特性,提供了更簡潔的語法來創(chuàng)建委托實(shí)例。.NET的ORM框架EF中有了Lambda表達(dá)式方便多了。
進(jìn)化:委托-->匿名方法-->Lambda
案例:下面案例是委托匿名方法和Lambda表達(dá)式三種使用案例
using System;using System.Linq;delegate int MathOperation(int a, int b);class Calculator{ public int Add(int a, int b) { return a + b; } public int Subtract(int a, int b) { return a - b; }}class Program{ static void Main(string[] args) { Calculator calculator = new Calculator(); MathOperation operation1 = calculator.Add; int result1 = operation1(10, 5); Console.WriteLine($"用委托方法計(jì)算: 10 + 5 = {result1}"); Func<int,int,int> operation2 = delegate (int a, int b) { return a - b; }; int result2 = operation2(15, 7); Console.WriteLine($"用匿名方法計(jì)算: 15 - 7 = {result2}"); Func<int,int,int> operation3 = (a, b) => a * b; int result3 = operation3(8, 6); Console.WriteLine($"用Lambda計(jì)算: 8 * 6 = {result3}"); Console.ReadKey(); }}
效果如下:

4、委托的BeginInvoke方法實(shí)現(xiàn)異步
委托的 BeginInvoke 方法和 EndInvoke 方法可以實(shí)現(xiàn)異步執(zhí)行委托方法。這允許委托的方法在后臺線程中執(zhí)行,而不會阻塞當(dāng)前線程。小編在之前的webform開發(fā)中遇到下載進(jìn)度條卡死的問題就是用它解決的。
案例:
using System;using System.Threading;
delegate void PrintDelegate(string message);class Program{ static void PrintMessage(string message) { for (int i = 0; i < 10000; i++) { Console.WriteLine(message); } } static void Main(string[] args) { PrintDelegate print = PrintMessage; // 使用委托的 BeginInvoke 方法來異步執(zhí)行方法 IAsyncResult result = print.BeginInvoke("執(zhí)行異步方法!", null, null); // 使用委托的 EndInvoke 方法獲取異步操作結(jié)果 print.EndInvoke(result);//這里不會卡死 Console.WriteLine("Begin 后的方法"); Console.ReadKey(); }}//由于控制臺不支持展示,大家可以自己研究一下。
二、事件
事件對象之間的松耦合通信
1、事件的定義與聲明
事件是委托的一種特殊應(yīng)用,用于實(shí)現(xiàn)發(fā)布-訂閱模型。使用event關(guān)鍵字可以聲明事件,并指定事件委托的類型。事件允許對象通知其他對象在特定情況下執(zhí)行操作,實(shí)現(xiàn)松耦合的通信機(jī)制。
public event TemperatureChangeHandler TemperatureChanged;
2、事件的訂閱與發(fā)布
訂閱事件的類(事件訂閱者)可以將其方法綁定到事件上,以便在事件觸發(fā)時(shí)執(zhí)行操作。事件的持有者(事件發(fā)布者)在適當(dāng)?shù)臅r(shí)機(jī)觸發(fā)事件,調(diào)用事件委托,從而通知所有訂閱者執(zhí)行相應(yīng)的操作。
案例:
using System;
class EventPublisher{ public event EventHandler<string> MessageSent; public void SendMessage(string message) { Console.WriteLine($"發(fā)送消息:{message}"); OnMessageSent(message); } protected virtual void OnMessageSent(string message) { MessageSent?.Invoke(this, message); }}
class EventSubscriber{ public void Subscribe(EventPublisher publisher) { publisher.MessageSent += HandleMessageSent; } public void Unsubscribe(EventPublisher publisher) { publisher.MessageSent -= HandleMessageSent; } private void HandleMessageSent(object sender, string message) { Console.WriteLine($"接收到消息:{message}"); }}
class Program{ static void Main(string[] args) { EventPublisher publisher = new EventPublisher(); EventSubscriber subscriber1 = new EventSubscriber(); EventSubscriber subscriber2 = new EventSubscriber(); subscriber1.Subscribe(publisher); subscriber2.Subscribe(publisher); publisher.SendMessage("你好,訂閱者們!"); Console.WriteLine("取消一個(gè)訂閱者的訂閱..."); subscriber1.Unsubscribe(publisher); publisher.SendMessage("再次打個(gè)招呼!");
Console.ReadKey(); }}
輸出:

3、事件的安全性與封裝
事件提供了一種封裝機(jī)制,使得事件只能被持有者觸發(fā),而不會被外部隨意調(diào)用。這樣可以確保事件只在控制的范圍內(nèi)使用,增強(qiáng)代碼的安全性和可維護(hù)性。
三、委托與事件的關(guān)系
事件是委托的一種特殊用法,用于實(shí)現(xiàn)發(fā)布者/訂閱者模式,實(shí)現(xiàn)對象之間的松耦合通信。委托是一種通用的類型,用于引用方法并執(zhí)行它們,而事件是委托的一種實(shí)現(xiàn),允許對象訂閱和響應(yīng)特定情況的通知,從而促進(jìn)模塊化和可維護(hù)的代碼設(shè)計(jì)。通過事件,對象可以在不直接依賴于其他對象的情況下,將重要信息傳遞給感興趣的觀察者。為了更好地理解委托和事件,我們可以以一個(gè)簡單的溫度監(jiān)測系統(tǒng)為例。假設(shè)有一個(gè)溫度監(jiān)測器對象,當(dāng)溫度發(fā)生變化時(shí),它可以通知其他對象執(zhí)行相應(yīng)的操作。using System;delegate void TemperatureChangeHandler(double temperature);class TemperatureMonitor{ public event TemperatureChangeHandler TemperatureChanged; private double currentTemperature; public double CurrentTemperature { get { return currentTemperature; } set { if (value != currentTemperature) { currentTemperature = value; OnTemperatureChanged(value); } } } protected virtual void OnTemperatureChanged(double temperature) { TemperatureChanged?.Invoke(temperature); }}class Program{ static void Main(string[] args) { TemperatureMonitor monitor = new TemperatureMonitor(); monitor.TemperatureChanged += OnTemperatureChanged; monitor.CurrentTemperature = 25.5; Console.ReadKey(); } static void OnTemperatureChanged(double temperature) { Console.WriteLine($"溫度變化 {temperature}°C"); }}
效果如下:

以上代碼示例使用了委托和事件,實(shí)現(xiàn)了觀察者模式。觀察者模式是一種行為設(shè)計(jì)模式,它定義了對象之間的一對多依賴關(guān)系,使得當(dāng)一個(gè)對象的狀態(tài)發(fā)生變化時(shí),所有依賴于它的對象都會得到通知并自動更新。在這個(gè)示例中,TemperatureMonitor 類充當(dāng)了被觀察者(發(fā)布者),Program 類中的 OnTemperatureChanged 方法充當(dāng)觀察者(訂閱者)
結(jié)語
委托和事件是C#中的重要概念,在C#中無論是實(shí)現(xiàn)回調(diào)機(jī)制、處理異步操作,還是實(shí)現(xiàn)事件驅(qū)動的架構(gòu),委托和事件都是不可缺的,每個(gè).NET開發(fā)者都應(yīng)該深入了解和熟練掌握。本文只列出了部分基礎(chǔ)知識點(diǎn),更多知識點(diǎn)大家可以到官網(wǎng)查詢。希望本文對你有所收獲,對于C#委托和事件的知識點(diǎn),你還知道哪些?歡迎留言討論或者吐槽本文。委托:learn.microsoft.com/zh-cn/dotnet/csharp/programming-guide/delegates/事件:learn.microsoft.com/zh-cn/dotnet/csharp/programming-guide/events/
閱讀原文:原文鏈接
該文章在 2025/2/18 16:24:47 編輯過