委托和事件


委托

  1. 委托的作用:

    1. 对签名相同的不同函数进行抽象,对它们进行封装从而达到代码复用的目的
    2. 异步调用和回调
  2. 如何使用,正常的使用可以分为三步:

    1. 定义委托 delegate int GetLengthDel(string input)

    2. 创建委托的实例并指向合适的方法 GetLengthDel del=GetLengthMethod 等于
      GetLengthDel del =new GetLengthDel(GetLengthMethod);

    3. 同步或者异步调用方法

      del.Invoke("input string");//
      del("input string");//和上面一行是等效的 ,而且都是同步调用
      //异步调用,事实上netcore已经禁止直接写这样的异步调用了;所以对这种过时的也不再讲解了
      //del.BeginInvoke
      
  3. 继承体系: 自定义委托-->System.MulticastDelegate-->System.Delegate
    System.MulticastDelegate 重要的内部成员包括

    1. _invocationList
      MulticastDelegate 定义了 私有的_invocationList字段,内容是 System.Delegate数组。
      可以通过 GetInvocationList公共方法获取到里面的内容; 而设置 _invocationList里的内容是通过 +=(调用 Delegate.Combine ) , -+ (调用 Delegate.Remove)来进行的.
    2. _target 从 基类 System.Delegate 继承而来。 当委托上绑定的是实例方法时,保存方法所在的实例对象的地址;当是静态方法时,值为null 。
    3. _methodPtr 从 基类 System.Delegate 继承而来。 保存绑定的方法内存地址 。
  4. 关于委托链条

    如果一个委托是绑定了多个方法(多播委托),并且这些方法是有返回值的,当执行完多个方法后,返回值是最后一个方法的返回值,而不是多个方法累计的值或者其他值。如果中间一个方法出现错误,绑定的后续方法将不会执行。
    想要实现累计值,可以通过GetInvocationList方法获取委托列表,循环调用,并自己维护累计值。
    另外注意: ① 如果委托绑定的方法大于1个, _invocationList才不等于 null; ② 委托内的_target_methodPtr总是等于_invocationList数组中的最后一个元素(System.Delegate对象)的_target_methodPtr

事件

  1. 事件是对委托的进一步封装,外部只能访问 += , -= ,
    类似属性提供的 Get , Set访问器 ,它提供的是 Add_xxx , Remove_xxx 对他可访问的委托进行维护 (其实也是调用 Delegate.CombineDelegate.Remove,) xxx一般为对应的委托名称。
  2. 作用:想比对外提供委托,增强了安全性和减少了不规范操作的带来的脆弱性。
  3. 使用:
    1.完全自定义
        //定义委托
        public delegate void MyClientEventHandler(string p);
        //定义事件
        public static event MyClientEventHandler MyClientEvent; 
        //绑定方法 省略见下面的例子
        //触发事件 省略见下面的例子
    
    1. 借助系统提供的 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