栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

详解C#委托和事件(二)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

详解C#委托和事件(二)

  一、当我们使用关键字delegate声明一个自定义委托类型时,实际上是声明了一个该名称的类类型,继承自抽象类System.MulticastDelegate,还包含实例方法Invoke、BeginInvoke、EndInvoke:

  public delegate void MyDelegate();

  

  其中的构造函数中第二个参数是native int类型的,这个是什么呢?我们接着看:

  我们知道在C#中任何方法都可以直接赋值给签名一致的委托实例,这个过程看似并不合理,按理来说C#中不支持直接获取函数的指针,其实这里是由编译器进行了取址操作,查看IL代码可知:

  MyDelegate myDelegate = myObj.MyFunc;

  

  可以看到由编译器为我们进行了构建委托实例的过程,而且这里调用了ldftn命令将实例方法MyFunc()的native int类型的非托管指针推到栈中,从而将该方法的指针传到委托的构造函数中;

  由于上面的构造函数存在C#中不支持的函数指针类型void(),所以不能在运行时使用Activator类中的方法创建委托实例,但在委托基类Delegate中存在静态方法CreateDelegate()调用非托管代码用于动态创建委托实例,命名空间System.Reflection中的方法信息类MethodInfo的实例方法CreateDelegate()也提供了类似的方式以在运行时动态构建委托实例:


    Type delegateType = typeof(MyDelegate);  //这里以可访问到的委托类型举例
    Delegate @delegate = Delegate.CreateDelegate(delegateType, myObj, "MyFunc");    //@delegate = typeof(MyClass).GetMethod("MyFunc").CreateDelegate(delegateType, myObj);    //添加其它委托实例
    @delegate = Delegate.Combine(@delegate, otherDelegate);    //调用委托    @delegate.DynamicInvoke();    //当指定的委托类型可访问时,可以将委托实例显式转换为指定的委托类型后使用()或Invoke()正常调用    //MyDelegate myDelegate = @delegate as MyDelegate;    //myDelegate();


  对委托实例或方法的+、+=操作实际上也是调用基类Delegate中的静态方法Combine()并将合成后的委托强制转换为原类型后返回,-、-=操作则是调用静态方法Remove();

   

  二、委托的异步调用:通过委托类型的实例方法BeginInvoke开启子线程并在该子线程中执行委托实例中的方法,以此种方式调用的委托实例中有且只能有一个方法,如果包含多个方法,会抛出异常ArgumentException:

  myDelegate.BeginInvoke(null, null); //其中第一个参数为AsyncCallback类型的回调函数

  如果需要异步调用一个委托实例中方法列表中的所有方法,需要先获取方法列表,再依次进行异步调用:

  Delegate[] delegates = myDelegate.GetInvocationList();
  for (int i = 0; i < delegates.Length; i++)
  {
    (delegates[i] as MyDelegate).BeginInvoke(null, null);
  }

  三、当调用委托时,如果方法列表中某个方法内引发异常且未在该方法体内捕获时,该异常将传递给委托的调用方,并且不再调用方法列表中的后面的方法,因此在方法体内捕获异常显得尤为重要;

  四、泛型中的委托:自定义泛型委托(Generic Delegate),将类型参数用作参数列表或返回值的类型:


  delegate void MyDelegate(T obj); //声明具有一个类型参数的泛型委托,参数列表中有一个参数  void MyGenericFunc(T obj) //声明一个泛型方法,参数列表中有一个参数  {
    //do…  }
  void MyFunc(string str)
  {
    //do…  }
  //声明泛型委托的实例,指定类型参数为string类型,此时可匹配的方法签名为void myFunc(string str)  MyDelegate myDelegate;
  //赋值一个指定类型参数为string的泛型方法  myDelegate = MyGenericFunc;
  //添加一个参数列表为string类型的具体方法  myDelegate += MyFunc;


  ※泛型委托同泛型类一样,需要在实例化时指定类型参数的类型;

  ※泛型委托的实例同具体委托的实例一样,只需要方法的参数列表和返回值类型相同即可进行匹配,因此不管目标方法是指定了符合要求类型的泛型方法还是具体方法都可以进行匹配;

原文作者:Minotauros

原文地址:https://www.cnblogs.com/minotauros/p/9806229.html

 


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/231015.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号