一、当我们使用关键字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 = ; i < delegates.Length; i++)
  {
    (delegates[i] as MyDelegate).BeginInvoke(null, null);
  }

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

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

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

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

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


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的认可是我写作的最大动力!

作者:Minotauros
出处:https://www.cnblogs.com/minotauros/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

详解C#委托和事件(二)的更多相关文章

  1. 详解C#泛型(二) 获取C#中方法的执行时间及其代码注入 详解C#泛型(一) 详解C#委托和事件(二) 详解C#特性和反射(四) 记一次.net core调用SOAP接口遇到的问题 C# WebRequest.Create 锚点“#”字符问题 根据内容来产生一个二维码

    详解C#泛型(二)   一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { ...

  2. 详解C#委托和事件(一)

    委托(Delegate)是安全封装方法的类型,类似于C和C++中的函数指针,与函数指针不同的是,委托是面向对象的.类型安全的和可靠的: 一.委托类型是CTS中五种基础类型之一,是一种引用类型,表示对具 ...

  3. 详解C#委托,事件与回调函数

    .Net编程中最经常用的元素,事件必然是其中之一.无论在ASP.NET还是WINFrom开发中,窗体加载(Load),绘制(Paint),初始化(Init)等等.“protected void Pag ...

  4. jQuery:详解jQuery中的事件(二)

    上一篇讲到jQuery中的事件,深入学习了加载DOM和事件绑定的相关知识,这篇主要深入讨论jQuery事件中的合成事件.事件冒泡和事件移除等内容. 接上篇jQuery:详解jQuery中的事件(一) ...

  5. 详解Vue 方法与事件处理器

      本篇文章主要介绍了详解Vue 方法与事件处理器 ,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 方法与事件处理器 方法处理器 可以用 v-on 指令监听 DOM 事件 ...

  6. ALSA声卡驱动中的DAPM详解之七:dapm事件机制(dapm event)

    前面的六篇文章,我们已经讨论了dapm关于动态电源管理的有关知识,包括widget的创建和初始化,widget之间的连接以及widget的上下电顺序等等.本章我们准备讨论dapm框架中的另一个机制:事 ...

  7. Android Launcher拖拽事件详解【android4.0--Launcher系列二】

    AndroidICS4.0版本的launcher拖 拽的流程,基本和2.3的相似.就是比2.3写的封装的接口多了一些,比如删除类的写法就多了个类.等等.4.0的改变有一些,但是不是特别大.这个月一 直 ...

  8. ALV详解:Function ALV(二)

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  9. 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-2 蒙特卡罗(二) 重要性采样

    书本内容:见相册 preface 还记的我们上一篇说的Monte Carlo 维度诅咒吗 上一篇算是二维的例子吧,大家看了之后是否想着写一个一维的Monte Carlo模拟积分?(我想了,没写出来) ...

随机推荐

  1. 20169207《linux内核原理与分析》第二周作业

    第一部分:学习MOOC网Linux内核分析的课程. 首先对冯诺依曼体系结构和存储程序计算机工作模型进行了了解,查阅资料,对冯诺依曼体系的特点与课堂上的相结合,真实明白了模型的特点. 在汇编C语言程序时 ...

  2. 正确的类引用却显示* cannot be resolved

    eclipse 出现的问题:在一个类中引入自己编写的类竟然说“cannot be resolved”,这非常明显不正常的! 解决办法:很简单,project->clean.我的问题就解决了. 至 ...

  3. 从MS Word到Windows Live Writer

    在做笔记的时候,喜欢使用Word进行排版及插入图片,但是当将笔记发布的时候,一般的网站是不支持直接将Word中的图片进行上传的,此时使用Windows Live Writer是一个不错的选择. 可是, ...

  4. VS2010与VS2013中的多字节编码与Unicode编码问题

    1. 多字节字符与单字节字符 char与wchar_t 我们知道C++基本数据类型中表示字符的有两种:char.wchar_t.  char叫多字节字符,一个char占一个字节,之所以叫多字节字符是因 ...

  5. shell工具-cut

    cut cut的工作就是“剪”,具体说就是在文件中负责剪切数据用的.cut命令从文件的每一行剪切字节.字符.和字段并将这些字节.字符和字段输出 基本用法 cut [参数] filename # 说明: ...

  6. python处理excel之读:xlrd模块

    # -*- coding:utf-8 -*- import xlrd path = r'D:/工作簿1(已自动还原).xlsx' # 打开excel文件读取数据 data = xlrd.open_wo ...

  7. 关于国密算法 SM1,SM2,SM3,SM4 的笔记

    国密即国家密码局认定的国产密码算法.主要有SM1,SM2,SM3,SM4.密钥长度和分组长度均为128位. SM1 为对称加密.其加密强度与AES相当.该算法不公开,调用该算法时,需要通过加密芯片的接 ...

  8. day05_雷神_函数进阶

    #day05 1.迭代器 1.1可迭代对象 str,list,tuple,dict,set,range,文件句柄 等都是可迭代对象 第一种方法:在该对象中,含有__iter__方法的就是可迭代对象,遵 ...

  9. CAD2007_DWG转PDF

    在使用CAD时,我们可能经常要将DWG转PDF格式,操作步骤如下: 1)打开需要转换的DWG文件 2)文件---->页面设置管理器----->修改----->(到“页面设置--模型” ...

  10. cpu信息查看

    # 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 # 查看物理CPU个数 cat /proc/cpuinfo| ...