.NET via C#笔记17——委托
一、委托的内部实现
C#中的委托是一种类型安全的回调函数,假设有这样一个委托:
internal delegate void Feedback(int value);
编译器会生成一个类:
internal class Feedback : MultiCastDelegate {
public Feedback(object @object, IntPtr method);
// 用于同步回调
public virtual void Invoke(int value);
// 用于异步回调
public virtual IAsyncResult BeginInvoke(int value, AsyncCallback callback, object @object);
public virtual void EndInvoke(IAsyncResult result);
}
当创建一个委托时,编译器会把静态函数,成员函数等转化为这个类的实例对象。
注意这里的修饰符是internal和deletage的修饰符是一致的。
二、委托链
MultiCastDelegate
再来看下MultiCastDelegate这个基类,它有三个重要字段:
| 字段 | 类型 | 说明 |
|---|---|---|
_target |
object |
如果引用一个实例方法,这里会存this |
_methodPtr |
IntPtr |
标示回调的方法 |
_invocationList |
object |
用于表示委托数组 |
这个类又继承自Delegate,这是C#的历史遗留问题,有些地方还需要用到Delegate作为参数类型。
Delegate.Combine
使用void Delegate.Combine(Delegate a, Delegate b)方法可以创建一个委托链。如果有一个参数为null返回值为非null的那个参数;如果都不是null,返回值为一个新的委托,其_invocaionList指向一个数组,数组的元素为这两个参数。
a |
b |
返回值 |
|---|---|---|
null |
delegate1 | delegate1 |
| delegate2 | null |
delegate2 |
| delegate1 | delegate2 | delegateChain |
Delegate.Remove
通过Remove方法可以删除委托(链)中从后向前找到的第一个符合条件的委托
- 如果没有了,返回
null。 - 如果只剩一个委托,返回这个委托。
- 如果还有多余一个委托,创建一个新的委托,和对应的数组,把剩下的委托拷贝进去。
带返回值的委托
如果委托类型带有返回值,对一个委托链进行Invoke操作会返回委托链中最后一个委托的调用结果。
显式控制委托链的调用
Delegate[] MultiCastDelegate.GetInvocationList()
三、语法糖和lambda表达式
- 可以用
+=和-=表示Delegate.Combine和Delegate.Remove方法。 - 隐式地使用静态函数或成员函数新建委托实例。
void foo() {}
void bar() {
Action action = foo;
action += foo;
action -= foo;
}
lambda表达式
int a = 0;
int b = 1;
Action action = ()=> { Console.WriteLine(a + b); };
分两种情况:
- 没有引用局部变量,lambda表达式会转化为类中的一个私有方法。
- 如果没有引用类的成员函数或成员变量,这是一个静态方法。
- 否则会成为一个成员方法。
- 如果lambda表达式引用了局部变量,编译器会为lambda表达式创建一个局部类。
- 类的成员变量用来存储引用的局部变量。
- 类的成员函数表示这个lambda表达式。
.NET via C#笔记17——委托的更多相关文章
- Ext.Net学习笔记17:Ext.Net GridPanel Selection
Ext.Net学习笔记17:Ext.Net GridPanel Selection 接下来是Ext.Net的GridPanel的另外一个功能:选择. 我们在GridPanel最开始的用法中已经见识过如 ...
- SQL反模式学习笔记17 全文搜索
目标:全文搜索 使用SQL搜索关键字,同时保证快速和精确,依旧是相当地困难. SQL的一个基本原理(以及SQL所继承的关系原理)就是一列中的单个数据是原子性的. 反模式:模式匹配 使用Like 或者正 ...
- JAVA自学笔记17
JAVA自学笔记17 1.Map接口 1)概述 将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值.可以存储键值对的元素 2)与Collection接口的不同: ①Map是双列的 ...
- golang学习笔记17 爬虫技术路线图,python,java,nodejs,go语言,scrapy主流框架介绍
golang学习笔记17 爬虫技术路线图,python,java,nodejs,go语言,scrapy主流框架介绍 go语言爬虫框架:gocolly/colly,goquery,colly,chrom ...
- 【C#进阶系列】17 委托
委托主要是为了实 现回调函数机制,可以理解为函数指针(唯一不同的在于多了委托链这个概念). 然而用的时候可以这么理解,但是委托的内部机制是比较复杂的. 一个委托的故事 delegate void ra ...
- [CLR via C#]17. 委托
回调函数是一种非常有用的编程机制,它已经存在很多年了.Microsoft .NET Framework通过委托(delegate)来提供一种回调机制.不同于其他平台(比如非托管C++)的回调机 ...
- (.NET高级课程笔记)委托、事件总结
1.委托的声明.实例化和调用 同样的,也可以把事务写成上面的形式 2.泛型委托---Func.Action 3.委托的意义:解耦 4.委托的意义:异步多线程 5.委托的意义:多播委托 6.观察者模 ...
- js-权威指南学习笔记17
第十七章 事件处理 1.事件处理程序或事件监听程序是处理或响应事件的函数. 2.事件对象是与特定事件相关且包含有关该事件详细信息的对象. 3.响应通过键盘改变焦点的表单元素在得到和失去焦点时会分别出发 ...
- Linux下汇编语言学习笔记17 ---
这是17年暑假学习Linux汇编语言的笔记记录,参考书目为清华大学出版社 Jeff Duntemann著 梁晓辉译<汇编语言基于Linux环境>的书,喜欢看原版书的同学可以看<Ass ...
随机推荐
- 「Luogu P3072 [USACO13FEB]周长Perimeter」
USACO的题目,感觉还是挺神奇的. 前置芝士 DFS(BFS)遍历:用来搜索(因为DFS好写,本文以DFS为准还不是因为作者懒) STL中的set(map)的基本用法:数据很大,不能直接存. 具体做 ...
- 学习笔记:中国剩余定理(CRT)
引入 常想起在空间里见过的一些智力题,这个题你见过吗: 一堆苹果,\(3\)个\(3\)个地取剩\(1\)个,\(5\)个\(5\)个地取剩\(1\)个,\(7\)个\(7\)个地取剩\(2\)个,苹 ...
- Shiro登录身份认证(从SecurityUtils.getSubject().login(token))到Realm的doGetAuthenticationInfo
ssm框架下,controller接收到登录请求交给Service并开始处理流程: 1.Service的login方法: @Service public class SysUserServiceImp ...
- Manjro i3 桌面 添加输入法 及无声音配置方法(This sound device does not have any capture controls.问题)
一.i3桌面添加输入法 1.把配置写在 /etc/environment中 export GTK_IM_MODULE=fcitx export QT_IM_MODULE=fcitx export XM ...
- Redis使用守护进程启动sentinel并指定其日志目录
正常redis-server可以通过配置文件来指定守护进程启动以及指定日志路径,但sentinel就不一样了.正常启动redis的sentinel时,进程会直接在前台跑,一退出sentinel进程就关 ...
- 十三: 悲观锁&乐观锁:解决丢失更新问题
悲观锁:认为丢失更新一定会出现,可以在查询的时候加入for update 认为丢失更新一定会出现,查询时: select * from account for update;for update : ...
- LINQ -- 匿名类型
匿名类型注意事项: 匿名类型只能和局部变量配合使用,不能用于成员. 由于匿名类型没有名字,我们必须使用var关键字作为变量类型. 不能设置匿名类型对象的属性.编译器为匿名类型穿件的属性是只读的. 除了 ...
- 论文阅读:Blink-Fast Connectivity Recovery Entirely in the Data Plane
1.背景 在网络中,链路故障的发生在所难免,为了降低故障带来的影响,就需要重新路由,将数据传输到合适的链路上.当因为链路故障发生处的不同,也有不同的解决方法. AS(Autonomous System ...
- node - multer 加图片后缀
var multer = require('multer') var storage = multer.diskStorage({ destination: function (req, file ...
- markdown超链接怎么写?
效果:我的微博 #上面的效果就是下面这种写法: [ 我的微博 ]( http://weibo.com/5833683560/profile?topnav=1&wvr=6&is_all= ...