详解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模拟积分?(我想了,没写出来) ...
随机推荐
- 《深入浅出MFC》系列之动态创建
/*************************************************************************************************** ...
- 安装BouncyCastle
对于Windows而言 将bcprov-jdk16-146.jar 复制到C:\Program Files\Java\jre6\lib\ext和C:\jdk1.6.0\jre\lib\ext目录下: ...
- webService之helloword(java)
webservice 远程数据交互技术 1.导入jar包(如果是 maven项目导入项目坐标) 2.创建服务 3.测试服务 我们使用maven来做测试服务 pom.xml文件 <project ...
- webView自适应及缩放
WebView wv=(WebView) findViewById(R.id.webView); wv.setVisibility(WebView.VISIBLE); WebSettings ws = ...
- 分形之C折线
前面讲了列维(levy)曲线,它是将一条线段不停地分形成两条长度相等且相互垂直的线段而生成.还有分形龙也是将一个线段对折成夹角为90度的两个线段.这一节展示的是将线段不停地分形成两条长度相等且夹角不固 ...
- 设置UITableView分割线距左边的间距
``` [self.tableView setSeparatorInset:UIEdgeInsetsZero]; [self.tableView setLayoutMargins:UIEdgeInse ...
- dispatch_async 和dispatch_sync
dispatch_sync(),同步添加操作.他是等待添加进队列里面的操作完成之后再继续执行. dispatch_queue_t concurrentQueue = dispatch_queue_cr ...
- .net core 使用 AspectCore 实现简易的AopCache。
(第一次写博客,好紧张!!!) 源码地址:传送门 项目中有很多缓存的需求,能自己定义缓存key和时间,能根据key去清理缓存. 网上找了一圈,有很多基于aop的缓存组件,但是都不满足我的需求.故造了个 ...
- 二、winForm-DataGridView操作——DataGridView 操作、属性说明
注册:Form加载窗体代码 /// <summary> /// 窗体加载Form1 /// </summary> /// <param name="sender ...
- SpringBoot2 使用Spring Session集群
有几种办法: 1.扩展指定server利用Servlet容器提供的插件功能,自定义HttpSession的创建和管理策略,并通过配置的方式替换掉默认的策略.缺点:耦合Tomcat/Jetty等Serv ...