委托和事件
委托
-
委托的作用:
- 对签名相同的不同函数进行抽象,对它们进行封装从而达到代码复用的目的
- 异步调用和回调
-
如何使用,正常的使用可以分为三步:
-
定义委托
delegate int GetLengthDel(string input)
-
创建委托的实例并指向合适的方法
GetLengthDel del=GetLengthMethod
等于
GetLengthDel del =new GetLengthDel(GetLengthMethod);
-
同步或者异步调用方法
del.Invoke("input string");// del("input string");//和上面一行是等效的 ,而且都是同步调用 //异步调用,事实上netcore已经禁止直接写这样的异步调用了;所以对这种过时的也不再讲解了 //del.BeginInvoke
-
-
继承体系:
自定义委托-->System.MulticastDelegate-->System.Delegate
System.MulticastDelegate
重要的内部成员包括- _invocationList
MulticastDelegate
定义了 私有的_invocationList
字段,内容是System.Delegate
数组。
可以通过GetInvocationList
公共方法获取到里面的内容; 而设置_invocationList
里的内容是通过+=
(调用Delegate.Combine
) ,-+
(调用Delegate.Remove
)来进行的. _target
从 基类System.Delegate
继承而来。 当委托上绑定的是实例方法时,保存方法所在的实例对象的地址;当是静态方法时,值为null 。_methodPtr
从 基类System.Delegate
继承而来。 保存绑定的方法内存地址 。
- _invocationList
-
关于委托链条
如果一个委托是绑定了多个方法(多播委托),并且这些方法是有返回值的,当执行完多个方法后,返回值是最后一个方法的返回值,而不是多个方法累计的值或者其他值。如果中间一个方法出现错误,绑定的后续方法将不会执行。
想要实现累计值,可以通过GetInvocationList方法获取委托列表,循环调用,并自己维护累计值。
另外注意: ① 如果委托绑定的方法大于1个, _invocationList才不等于 null; ② 委托内的_target
和_methodPtr
总是等于_invocationList数组中的最后一个元素(System.Delegate
对象)的_target
和_methodPtr
。
事件
- 事件是对委托的进一步封装,外部只能访问
+=
,-=
,
类似属性提供的Get
,Set
访问器 ,它提供的是Add_xxx
,Remove_xxx
对他可访问的委托进行维护 (其实也是调用Delegate.Combine
和Delegate.Remove,
)xxx
一般为对应的委托名称。 - 作用:想比对外提供委托,增强了安全性和减少了不规范操作的带来的脆弱性。
- 使用:
1.完全自定义//定义委托 public delegate void MyClientEventHandler(string p); //定义事件 public static event MyClientEventHandler MyClientEvent; //绑定方法 省略见下面的例子 //触发事件 省略见下面的例子
- 借助系统提供的 EventHandler
#region 非泛型 // 定义非泛型事件 public event EventHandler MyEvent; //绑定方法 MyEvent+=NewCarIsHere; //触发事件 MyEvent?.Invoke(this,new System.EventArgs()); //绑定到事件的方法 public void NewCarIsHere(object sender, CarInfoEventArgs e) => Console.WriteLine($" MyEvent happened "); #endregion #region 泛型事件 // 定义泛型事件 public event EventHandler
CarArrivaledEvent; //定义泛型参数 public class CarInfoEventArgs : EventArgs { public CarInfoEventArgs(string car) => Car = car; public string Car { get; } } //绑定方法 CarArrivaledEvent+=CarArrivaled; //触发事件 CarArrivaledEvent?.Invoke(this, new CarInfoEventArgs(car)); //绑定到事件的方法 public void CarArrivaled(object sender, CarInfoEventArgs e) => Console.WriteLine($" {e.Car} Arrivaled "); #endregion