详解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 = ; 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#委托和事件(二)的更多相关文章
- 详解C#泛型(二) 获取C#中方法的执行时间及其代码注入 详解C#泛型(一) 详解C#委托和事件(二) 详解C#特性和反射(四) 记一次.net core调用SOAP接口遇到的问题 C# WebRequest.Create 锚点“#”字符问题 根据内容来产生一个二维码
详解C#泛型(二) 一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { ...
- 详解C#委托和事件(一)
委托(Delegate)是安全封装方法的类型,类似于C和C++中的函数指针,与函数指针不同的是,委托是面向对象的.类型安全的和可靠的: 一.委托类型是CTS中五种基础类型之一,是一种引用类型,表示对具 ...
- 详解C#委托,事件与回调函数
.Net编程中最经常用的元素,事件必然是其中之一.无论在ASP.NET还是WINFrom开发中,窗体加载(Load),绘制(Paint),初始化(Init)等等.“protected void Pag ...
- jQuery:详解jQuery中的事件(二)
上一篇讲到jQuery中的事件,深入学习了加载DOM和事件绑定的相关知识,这篇主要深入讨论jQuery事件中的合成事件.事件冒泡和事件移除等内容. 接上篇jQuery:详解jQuery中的事件(一) ...
- 详解Vue 方法与事件处理器
本篇文章主要介绍了详解Vue 方法与事件处理器 ,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 方法与事件处理器 方法处理器 可以用 v-on 指令监听 DOM 事件 ...
- ALSA声卡驱动中的DAPM详解之七:dapm事件机制(dapm event)
前面的六篇文章,我们已经讨论了dapm关于动态电源管理的有关知识,包括widget的创建和初始化,widget之间的连接以及widget的上下电顺序等等.本章我们准备讨论dapm框架中的另一个机制:事 ...
- Android Launcher拖拽事件详解【android4.0--Launcher系列二】
AndroidICS4.0版本的launcher拖 拽的流程,基本和2.3的相似.就是比2.3写的封装的接口多了一些,比如删除类的写法就多了个类.等等.4.0的改变有一些,但是不是特别大.这个月一 直 ...
- ALV详解:Function ALV(二)
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-2 蒙特卡罗(二) 重要性采样
书本内容:见相册 preface 还记的我们上一篇说的Monte Carlo 维度诅咒吗 上一篇算是二维的例子吧,大家看了之后是否想着写一个一维的Monte Carlo模拟积分?(我想了,没写出来) ...
随机推荐
- bat文件命令
- html5打开摄像头并用canvas模拟拍照 - 转
<video id="video" width="640" height="480" autoplay></video&g ...
- iOS中的序列帧动画
UIImageView对象的有一个animationImages属性,将图片数组赋值给该属性即可.如图: 控制动画的播放方法是:[ ___ startAnimating]; 控制动画的停止方法是:[ ...
- hdu 1695 GCD 【莫比乌斯函数】
题目大意:给你 a , b , c , d , k 五个值 (题目说明了 你可以认为 a=c=1) x 属于 [1,b] ,y属于[1,d] 让你求有多少对这样的 (x,y)满足gcd(x,y)= ...
- spring 框架整合mybatis的源码分析
问题:spring 在整合mybatis的时候,我们是看不见sqlSessionFactory,和sqlsession(sqlsessionTemplate 就是sqlsession的具体实现)的,这 ...
- 转:log4j的使用简介
spring使用log4j,可以有2种方法. 1.在web.xml里不做任何配置. log4j.properties放在classpath根目录下, 这时候生成的日志文件就没有相对路径,如果写相对路径 ...
- 数字签名、数字证书的原理以及证书的获得java版
数字签名原理简介(附数字证书) 首先要了解什么叫对称加密和非对称加密,消息摘要这些知识. 1. 非对称加密 在通信双方,如果使用非对称加密,一般遵从这样的原则:公钥加密,私钥解密.同时,一般一个密钥加 ...
- unigui回车代替TAB
unigui回车代替TAB 在业务系统中常常使用回车键(Enter)替代Tab键完成焦点跳转,在uniGUI下,可以不用代码,直接使用TUniForm的NavigateKeys进行设置: 其中Next ...
- 使用docker部署WordPress博客系统(win10企业版)
docker介绍: docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相 ...
- Windows核心编程:第6章 线程基础
Github https://github.com/gongluck/Windows-Core-Program.git //第6章 线程基础.cpp: 定义应用程序的入口点. // #include ...