C# 委托/事件/lambda

概念 

委托

  1. 定义委托编译器会自动生成一个类派生自System.MulticastDelegate

这个类包含4个方法:一个构造器、Invoke、BeginInvoke、EndInvoke。

  1. 调用委托的时候实际上执行的是 Invoke方法。

MulticastDelegate有三个重要字段:

  1. _targetSystem.Object):当委托对象包装的是一个静态方法,这个字段为null。当委托对象包装一个实例方法,这个字段引用的是回调方法要操作的对象
  2. _methodPtrSystem.IntPtr):这是一个 System.IntPtr 类型的字段,它存储了方法的内存地址。这个内存地址是 CLR 用来标识委托所引用方法的唯一标识。
  3. _invocationListSystem.Object):该字段通常为null,构造委托链时它引用一个委托数组。若不为null,Invoke的时候会遍历委托数组依次调用。可以使用GetInvocationList接口获取这个数组。

用委托回调多个方法(委托链)

使用Delegate.Combine 或者用 += 可以将多个委托合并成委托链。每次添加时 _invocationList都会新建一个新的委托数组,数组里存放所有委托,之前引用的数组等待被GC回收。

使用Delegate.Remove 或者 -= 可以从委托链中删除一个委托,通过 _target和_methodPtr找到匹配的委托后,_invocationList同样会引用一个新建数组,新数组不包含移除的那个委托。

若委托链中只剩一个委托,删除成功后返回null。

C#自带的委托

1)Action:无返回值委托,最多支持16个泛型参数。

2)Func:返回一个泛型,最多支持16个泛型参数,最后一个参数必须是返回值类型。

Unity自带的委托

1)UnityAction:无返回值,最多支持4个泛型参数。

2)UnityEvent:Unity对UnityAction的封装。

泛型委托的协变/逆变参数类型

使用 in 关键字表示逆变,参数可以使用类型的派生类。

使用 out 关键字表示协变,参数可以使用类型的基类。

事件

事件是委托的包装器,内部维护了一个私有的委托链。向事件注册监听的时候其实就是往委托链里面添加一个委托,当事件触发的时候,会遍历委托链依次调用。


示例 

在某个管理器中给出一个获取Sprite的方法 ,因为addressables异步加载资源,所以 获取的信息必须在资源回调中返回,那么直接使用lambda表达式便于回调的赋值

 public void GetCustomerSprite(int id, Action callback)
 {
     AddressablesMgr.GetInstance().LoadAssetAsync(customerDataDic[id].bigImgRes, (obj) =>
     {
         callback(obj.Result);
     });
 }

外部调用代码

        InventoryData.GetInstance().GetCustomerSprite(id, (sprite) =>
        {
            bigImg.sprite = sprite;
        });

你可能感兴趣的:(c#)