翼度科技»论坛 编程开发 .net 查看内容

每个.NET开发都应掌握的C#委托事件知识点

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
上篇文章讲述了C#接口的知识点,本文将介绍C#委托事件知识点。C#作为.NET开发的核心语言之一,提供了丰富的特性来支持面向对象编程和事件驱动的模型。其中,委托和事件是C#中不可或缺的关键概念,每个.NET开发者都应该深入理解它们的作用和用法。委托和事件密不可分,所以本文将委托和事件的知识点一起介绍,并通过一些示例来帮助开发者更好地掌握这些重要的概念。
一、委托
委托让方法引用的灵活利用
1、委托的定义与使用
委托是一种数据类型,用于持有对一个或多个方法的引用。通过委托,你可以将方法作为参数传递给其他方法,实现回调机制,实现方法的动态调用。使用`delegate`关键字可以声明委托类型,并创建委托实例来绑定具体方法。
  1. using System;
  2. //定义一个委托
  3. delegate int CalculatorDelegate(int a, int b);
  4. class Calculator
  5. {
  6.     public int Add(int a, int b)
  7.     {
  8.         return a + b;
  9.     }
  10.     public int Subtract(int a, int b)
  11.     {
  12.         return a - b;
  13.     }
  14. }
  15. class Program
  16. {
  17.     static void Main(string[] args)
  18.     {
  19.         Calculator calculator = new Calculator();
  20.         // 声明委托实例,并绑定到 Add 方法
  21.         CalculatorDelegate funDelegate = new CalculatorDelegate(calculator.Add);
  22.         // 使用委托调用方法
  23.         int result = funDelegate (5, 2);
  24.         Console.WriteLine($"5 + 2 = {result}");
  25.         // 将委托重新绑定到 Subtract 方法
  26.         funDelegate = calculator.Subtract;
  27.         // 使用委托调用不同的方法
  28.         result = funDelegate(8, 6);
  29.         Console.WriteLine($"8 - 6 = {result}");
  30.     }
  31. }
复制代码
使用try.dot.net的测试结果:

2、委托的多播
委托不仅可以持有单个方法的引用,还可以用于多播,即将多个方法绑定到同一个委托实例。多播委托允许按顺序调用这些方法,实现一次触发多个方法的功能。
  1. using System;
  2. delegate void MyDelegate(); // 定义委托
  3. class EventPublisher
  4. {
  5.     private MyDelegate eventHandlers; // 多播委托实例
  6.     public void AddHandler(MyDelegate handler)
  7.     {
  8.         eventHandlers += handler; // 添加委托方法到多播链
  9.     }
  10.     public void RemoveHandler(MyDelegate handler)
  11.     {
  12.         eventHandlers -= handler; // 从多播链中移除委托方法
  13.     }
  14.     public void RaiseEvent()
  15.     {
  16.         Console.WriteLine("事件发布者正在引发事件...");
  17.         eventHandlers?.Invoke(); // 调用多播链中的委托方法
  18.     }
  19. }
  20. class Program
  21. {
  22.     static void Main(string[] args)
  23.     {
  24.         EventPublisher publisher = new EventPublisher();
  25.         // 添加多个事件处理程序到多播链
  26.         publisher.AddHandler(Method1);
  27.         publisher.AddHandler(Method2);
  28.         publisher.AddHandler(Method3);
  29.         // 触发事件,调用多播链中的所有方法
  30.         publisher.RaiseEvent();
  31.         // 移除一个事件处理程序
  32.         publisher.RemoveHandler(Method2);
  33.         // 再次触发事件
  34.         publisher.RaiseEvent();
  35.         Console.ReadKey();
  36.     }
  37.     static void Method1()
  38.     {
  39.         Console.WriteLine("方法1运行.");
  40.     }
  41.     static void Method2()
  42.     {
  43.         Console.WriteLine("方法2运行.");
  44.     }
  45.     static void Method3()
  46.     {
  47.         Console.WriteLine("方法3运行.");
  48.     }
  49. }
复制代码
输出结果:

3、 匿名方法与Lambda表达式
C# 2.0 引入了匿名方法,允许在没有显示声明方法的情况下传递代码块作为委托参数。而Lambda表达式则是C# 3.0 的新特性,提供了更简洁的语法来创建委托实例。.NET的ORM框架EF中有了Lambda表达式方便多了。
进化:委托-->匿名方法-->Lambda
案例:下面案例是委托匿名方法和Lambda表达式三种使用案例
  1. using System;
  2. using System.Linq;
  3. delegate int MathOperation(int a, int b);
  4. class Calculator
  5. {
  6.     public int Add(int a, int b)
  7.     {
  8.         return a + b;
  9.     }
  10.     public int Subtract(int a, int b)
  11.     {
  12.         return a - b;
  13.     }
  14. }
  15. class Program
  16. {
  17.     static void Main(string[] args)
  18.     {
  19.         Calculator calculator = new Calculator();
  20.         // 1、使用委托和实例方法 Add
  21.         MathOperation operation1 = calculator.Add;
  22.         int result1 = operation1(10, 5);
  23.         Console.WriteLine($"用委托方法计算: 10 + 5 = {result1}");
  24.         // 2、使用匿名方法进行减法运算
  25.         //MathOperation  operation2 = delegate (int a, int b)
  26.         Func<int,int,int> operation2 = delegate (int a, int b)//内置Func
  27.         {
  28.             return a - b;
  29.         };
  30.         int result2 = operation2(15, 7);
  31.         Console.WriteLine($"用匿名方法计算: 15 - 7 = {result2}");
  32.         // 3、使用 Lambda 表达式进行乘法运算
  33.         //MathOperation operation3 = (a, b) => a * b;//委托变量
  34.         Func<int,int,int> operation3 = (a, b) => a * b;//内置Func
  35.         int result3 = operation3(8, 6);
  36.         Console.WriteLine($"用Lambda计算: 8 * 6 = {result3}");
  37.         Console.ReadKey();
  38.     }
  39. }
  40. //欢迎关注公众号:DOTNET开发跳槽,领取海量面试题。
  41. //加微信号xbhpnet入群交流.NET求职和技术
复制代码
效果如下:

4、委托的BeginInvoke方法实现异步
委托的 BeginInvoke 方法和 EndInvoke 方法可以实现异步执行委托方法。这允许委托的方法在后台线程中执行,而不会阻塞当前线程。小编在之前的webform开发中遇到下载进度条卡死的问题就是用它解决的。
案例:
  1. using System;
  2. using System.Threading;
  3. delegate void PrintDelegate(string message);
  4. class Program
  5. {
  6.     static void PrintMessage(string message)
  7.     {
  8.         for (int i = 0; i < 10000; i++)
  9.         {
  10.             Console.WriteLine(message);
  11.         }
  12.     }
  13.     static void Main(string[] args)
  14.     {
  15.         PrintDelegate print = PrintMessage;
  16.         // 使用委托的 BeginInvoke 方法来异步执行方法
  17.         IAsyncResult result = print.BeginInvoke("执行异步方法!", null, null);
  18.         // 使用委托的 EndInvoke 方法获取异步操作结果
  19.         print.EndInvoke(result);//这里不会卡死
  20.         Console.WriteLine("Begin 后的方法");
  21.         Console.ReadKey();
  22.     }
  23. }
  24. //由于控制台不支持展示,大家可以自己研究一下。
复制代码
二、事件
事件对象之间的松耦合通信
1、事件的定义与声明
事件是委托的一种特殊应用,用于实现发布-订阅模型。使用event关键字可以声明事件,并指定事件委托的类型。事件允许对象通知其他对象在特定情况下执行操作,实现松耦合的通信机制。
  1.  //声名
  2. public event TemperatureChangeHandler TemperatureChanged;
复制代码
2、事件的订阅与发布
订阅事件的类(事件订阅者)可以将其方法绑定到事件上,以便在事件触发时执行操作。事件的持有者(事件发布者)在适当的时机触发事件,调用事件委托,从而通知所有订阅者执行相应的操作。
案例:
  1. using System;
  2. // 定义事件发布者类
  3. class EventPublisher
  4. {
  5.     // 声明事件委托
  6.     public event EventHandler<string> MessageSent;
  7.     // 触发事件的方法
  8.     public void SendMessage(string message)
  9.     {
  10.         Console.WriteLine($"发送消息:{message}");
  11.         OnMessageSent(message);
  12.     }
  13.     // 触发事件的保护方法
  14.     protected virtual void OnMessageSent(string message)
  15.     {
  16.         MessageSent?.Invoke(this, message); // 调用事件
  17.     }
  18. }
  19. // 定义事件订阅者类
  20. class EventSubscriber
  21. {
  22.     public void Subscribe(EventPublisher publisher)
  23.     {
  24.         // 订阅事件
  25.         publisher.MessageSent += HandleMessageSent;
  26.     }
  27.     public void Unsubscribe(EventPublisher publisher)
  28.     {
  29.         // 取消订阅事件
  30.         publisher.MessageSent -= HandleMessageSent;
  31.     }
  32.     // 事件处理方法
  33.     private void HandleMessageSent(object sender, string message)
  34.     {
  35.         Console.WriteLine($"接收到消息:{message}");
  36.     }
  37. }
  38. class Program
  39. {
  40.     static void Main(string[] args)
  41.     {
  42.         EventPublisher publisher = new EventPublisher();
  43.         EventSubscriber subscriber1 = new EventSubscriber();
  44.         EventSubscriber subscriber2 = new EventSubscriber();
  45.         // 订阅事件
  46.         subscriber1.Subscribe(publisher);
  47.         subscriber2.Subscribe(publisher);
  48.         // 发布事件
  49.         publisher.SendMessage("你好,订阅者们!");
  50.         Console.WriteLine("取消一个订阅者的订阅...");
  51.         // 取消订阅一个订阅者
  52.         subscriber1.Unsubscribe(publisher);
  53.         // 发布事件
  54.         publisher.SendMessage("再次打个招呼!");
  55.         Console.ReadKey();
  56.     }
  57. }
复制代码
输出:

3、事件的安全性与封装
事件提供了一种封装机制,使得事件只能被持有者触发,而不会被外部随意调用。这样可以确保事件只在控制的范围内使用,增强代码的安全性和可维护性。
三、委托与事件的关系
事件是委托的一种特殊用法,用于实现发布者/订阅者模式,实现对象之间的松耦合通信。委托是一种通用的类型,用于引用方法并执行它们,而事件是委托的一种实现,允许对象订阅和响应特定情况的通知,从而促进模块化和可维护的代码设计。通过事件,对象可以在不直接依赖于其他对象的情况下,将重要信息传递给感兴趣的观察者。
下面将用一个案例来理解委托和事件
为了更好地理解委托和事件,我们可以以一个简单的温度监测系统为例。假设有一个温度监测器对象,当温度发生变化时,它可以通知其他对象执行相应的操作。
  1. using System;
  2. // 定义一个委托,用于处理温度变化事件
  3. delegate void TemperatureChangeHandler(double temperature);
  4. // 温度监控类
  5. class TemperatureMonitor
  6. {
  7.     // 定义事件,将委托作为事件处理程序
  8.     public event TemperatureChangeHandler TemperatureChanged;
  9.     private double currentTemperature; // 当前温度
  10.     // 属性,获取和设置当前温度,当温度发生变化时触发事件
  11.     public double CurrentTemperature
  12.     {
  13.         get { return currentTemperature; }
  14.         set
  15.         {
  16.             if (value != currentTemperature)
  17.             {
  18.                 currentTemperature = value;
  19.                 OnTemperatureChanged(value); // 温度变化时调用事件
  20.             }
  21.         }
  22.     }
  23.     // 触发温度变化事件的方法
  24.     protected virtual void OnTemperatureChanged(double temperature)
  25.     {
  26.         TemperatureChanged?.Invoke(temperature); // 调用事件处理程序
  27.     }
  28. }
  29. class Program
  30. {
  31.     static void Main(string[] args)
  32.     {
  33.         TemperatureMonitor monitor = new TemperatureMonitor();
  34.         // 订阅温度变化事件,将方法 OnTemperatureChanged 作为事件处理程序
  35.         monitor.TemperatureChanged += OnTemperatureChanged;
  36.         // 改变当前温度,触发事件
  37.         monitor.CurrentTemperature = 25.5;
  38.         Console.ReadKey();
  39.     }
  40.     // 温度变化事件处理程序
  41.     static void OnTemperatureChanged(double temperature)
  42.     {
  43.         Console.WriteLine($"温度变化 {temperature}°C");
  44.     }
  45. }
  46. //案例参考:C#委托事件-张子阳
复制代码
效果如下:

以上代码示例使用了委托和事件,实现了观察者模式。观察者模式是一种行为设计模式,它定义了对象之间的一对多依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。在这个示例中,TemperatureMonitor 类充当了被观察者(发布者),Program 类中的 OnTemperatureChanged 方法充当观察者(订阅者)
结语
委托和事件是C#中的重要概念,在C#中无论是实现回调机制、处理异步操作,还是实现事件驱动的架构,委托和事件都是不可缺的,每个.NET开发者都应该深入了解和熟练掌握。本文只列出了部分基础知识点,更多知识点大家可以到官网查询。
希望本文对你有所收获,对于C#委托和事件的知识点,你还知道哪些?欢迎留言讨论或者吐槽本文。
参考:
1、chatgpt
2、微软官方文档 :
委托:learn.microsoft.com/zh-cn/dotnet/csharp/programming-guide/delegates/
事件:learn.microsoft.com/zh-cn/dotnet/csharp/programming-guide/events/
  1. 来源公众号:DotNet开发跳槽
复制代码
来源:https://www.cnblogs.com/xbhp/archive/2023/08/21/17645729.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具