C#——Delegate(委托)与Event(事件)
- 前言
- 一、Delegate(委托)
- 1.是什么?
- 2.怎么用?
- Example 1:无输入无返回值
- Example 2:有输入
- Example 3:有返回值
- Example 4:多播委托
- Example 5:处理有返回值的多播委托的结果
- 二、Event(事件)
- 1.是什么?
- 2.怎么用?
- Example 1:简单案例
- Example 2:流程中重复绑定同一方法的优化
- 三、总结
前言
在刚开始学习C#的时候,常常委托与事件傻傻分不清,经常性的混为一谈。他们功能相似,应用场景却不太一样,下面就从分别的介绍再到差异的分析一起来看看啪。
一、Delegate(委托)
1.是什么?
委托是 C# 中的一种类型,它代表了对一个或多个方法的引用。它类似于函数指针,在编程中可以将方法作为参数传递给其他方法。
2.怎么用?
看个简单的委托应用:
例子是基于C#控制台编写的
Example 1:无输入无返回值
申明委托类型:
delegate void write();
定义一个委托变量:
static write w;
写一个和申明的委托变量相同输入输出类型的函数:
public static void writeS(){Console.WriteLine(1);}
给委托绑定方法并调用:
static void Main(string[] args){w += writeS; //绑定w(); //调用,会运行绑定的方法(writeS)Console.ReadKey();}
结果:
直接打印一个1。
Example 2:有输入
申明委托类型:
delegate void write(int a,int b);
定义一个委托变量:
static write w;
写一个和申明的委托变量相同输入输出类型的函数:
public static void writeS(int a,int b){Console.WriteLine(a + b);}
给委托绑定方法并调用:
static void Main(string[] args){w += writeS; //绑定w(1,2); //调用,会运行绑定的方法(writeS)Console.ReadKey();}
结果:
直接打印一个3。
Example 3:有返回值
申明委托类型:
delegate bool write(int a,int b);
定义一个委托变量:
static write w;
写一个和申明的委托变量相同输入输出类型的函数:
public static bool writeS(int a,int b){return a > b;}
给委托绑定方法并调用:
static void Main(string[] args){w += writeS; //绑定Console.WriteLine( w(1,2)); //调用,会运行绑定的方法(writeS)Console.ReadKey();}
结果:
直接打印一个False。
Example 4:多播委托
在此讨论比较特殊的有返回值的多播委托
简单理解,就是把多个方法绑定到一个委托,委托触发将触发所有绑定的方法。
申明委托类型:
delegate bool write(int a,int b);
定义一个委托变量:
static write w;
写一个和申明的委托变量相同输入输出类型的函数:
public static bool writeS(int a,int b){return a > b;}public static bool writeS2(int a,int b){return a < b;}
给委托绑定方法并调用:
static void Main(string[] args){w += writeS; //绑定w += writeS2; //绑定Console.WriteLine( w(1,2)); //调用,会运行绑定的方法(writeS和writeS2)Console.ReadKey();}
结果:
直接打印一个True。
此时可以注意到,我绑定了两个带返回值的方法,第一个(writeS)返回false,第二个(writeS2)返回true。实际页面打印的是True。多次测试后可以发现,当多播委托带有返回值时且有多个绑定方法时,返回值将以最后一个添加绑定的为最终结果。
Example 5:处理有返回值的多播委托的结果
为解决Example4中绑定多个返回值的方法时,可以在外部进行数据分析来获取最终的结果。
新增代码如下:
static bool JudgeRet(int a,int b){bool ret = true;if (w != null){foreach (write item in w.GetInvocationList())//变量委托里面的所有绑定的方法列表,获取结果并处理结果{ret = ret & item(a,b);//处理流程,有false就为false。}}return ret;}
完整代码如下:
class Program{delegate bool write(int a,int b);static write w;static void Main(string[] args){w += writeS;w += writeS2;Console.WriteLine(JudgeRet(1,2));Console.ReadKey();}static bool JudgeRet(int a,int b){bool ret = true;if (w != null){foreach (write item in w.GetInvocationList()){ret = ret & item(a,b);}}return ret;}public static bool writeS(int a,int b){return a > b;}public static bool writeS2(int a, int b){return a < b;}}
结果:
有false则为false。
二、Event(事件)
1.是什么?
事件是一种特殊类型的委托,用于实现观察者模式。它限制了委托的使用,只允许外部类通过 += 和 -= 运算符订阅和取消订阅事件。它提供了一种安全的订阅机制,防止外部类直接调用委托列表。只有持有类可以触发事件。
本质上:事件是对委托的封装,提供了一种更安全、更封装的方式来进行观察者模式的实现。
2.怎么用?
Example 1:简单案例
全部代码以及解析:
public delegate bool write(int a, int b); //定义的委托类型public class test //测试类,体现事件只能在持有类中触发{write w; //委托对象public event write WriteEvent; //事件对象public void triger(int a, int b) //触发事件{WriteEvent?.Invoke(a, b); //判断事件是否为空,不为空则触发}}class Program{static void Main(string[] args){test t = new test(); //生成测试类实例//此时在外部,无法访问到委托实例w,只能通过事件WriteEvent绑定t.WriteEvent += writeS; //绑定方法t.WriteEvent += writeS;t.WriteEvent += writeS; //绑定了多次相同的方法t.WriteEvent += writeS;t.triger(1, 2); //触发Console.ReadKey();}public static bool writeS(int a, int b){Console.WriteLine(a + b);return a > b;}}
结果如下:
发现多次绑定同一方法时,无法判断重复,绑定几次执行几次。
上文需要注意的是,WriteEvent?.Invoke(a, b);直接调用了事件名,在简略声明中,可以 使用Invoke调用事件,但也仅限于事件拥有类内部使用。
Example 2:流程中重复绑定同一方法的优化
优化事件代码如下:
public delegate bool write(int a, int b);public class test{write w;public event write WriteEvent{add{if (w != null && w.GetInvocationList().Contains(value)){return;}w += value;}remove{w -= value;}}public void triger(int a, int b){w(a, b); //此处因为重写了Add以及Remove无法使用WriteEvent?.Invoke(a, b);}}class Program{static void Main(string[] args){test t = new test();t.WriteEvent += writeS;t.WriteEvent += writeS;t.WriteEvent += writeS;t.WriteEvent += writeS;t.triger(1, 2);Console.ReadKey();}public static bool writeS(int a, int b){Console.WriteLine(a + b);return a > b;}}
结果:
三、总结
简单点:
- 委托允许你将方法作为参数传递或存储,可以被直接调用。
- 事件是一种特殊类型的委托,提供更安全、封装的订阅机制,只允许持有类触发事件(且必须是简单声明)。