一、委托的内部实现

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方法可以删除委托(链)中从后向前找到的第一个符合条件的委托

  1. 如果没有了,返回null
  2. 如果只剩一个委托,返回这个委托。
  3. 如果还有多余一个委托,创建一个新的委托,和对应的数组,把剩下的委托拷贝进去。

带返回值的委托

如果委托类型带有返回值,对一个委托链进行Invoke操作会返回委托链中最后一个委托的调用结果。

显式控制委托链的调用

Delegate[] MultiCastDelegate.GetInvocationList()

三、语法糖和lambda表达式

  1. 可以用+=-=表示Delegate.CombineDelegate.Remove方法。
  2. 隐式地使用静态函数或成员函数新建委托实例。
    void foo() {}
    void bar() {
    Action action = foo;
    action += foo;
    action -= foo;
    }

lambda表达式

int a = 0;
int b = 1;
Action action = ()=> { Console.WriteLine(a + b); };

分两种情况:

  1. 没有引用局部变量,lambda表达式会转化为类中的一个私有方法。

    1. 如果没有引用类的成员函数或成员变量,这是一个静态方法。
    2. 否则会成为一个成员方法。
  2. 如果lambda表达式引用了局部变量,编译器会为lambda表达式创建一个局部类。
    1. 类的成员变量用来存储引用的局部变量。
    2. 类的成员函数表示这个lambda表达式。

.NET via C#笔记17——委托的更多相关文章

  1. Ext.Net学习笔记17:Ext.Net GridPanel Selection

    Ext.Net学习笔记17:Ext.Net GridPanel Selection 接下来是Ext.Net的GridPanel的另外一个功能:选择. 我们在GridPanel最开始的用法中已经见识过如 ...

  2. SQL反模式学习笔记17 全文搜索

    目标:全文搜索 使用SQL搜索关键字,同时保证快速和精确,依旧是相当地困难. SQL的一个基本原理(以及SQL所继承的关系原理)就是一列中的单个数据是原子性的. 反模式:模式匹配 使用Like 或者正 ...

  3. JAVA自学笔记17

    JAVA自学笔记17 1.Map接口 1)概述 将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值.可以存储键值对的元素 2)与Collection接口的不同: ①Map是双列的 ...

  4. golang学习笔记17 爬虫技术路线图,python,java,nodejs,go语言,scrapy主流框架介绍

    golang学习笔记17 爬虫技术路线图,python,java,nodejs,go语言,scrapy主流框架介绍 go语言爬虫框架:gocolly/colly,goquery,colly,chrom ...

  5. 【C#进阶系列】17 委托

    委托主要是为了实 现回调函数机制,可以理解为函数指针(唯一不同的在于多了委托链这个概念). 然而用的时候可以这么理解,但是委托的内部机制是比较复杂的. 一个委托的故事 delegate void ra ...

  6. [CLR via C#]17. 委托

        回调函数是一种非常有用的编程机制,它已经存在很多年了.Microsoft .NET Framework通过委托(delegate)来提供一种回调机制.不同于其他平台(比如非托管C++)的回调机 ...

  7. (.NET高级课程笔记)委托、事件总结

      1.委托的声明.实例化和调用 同样的,也可以把事务写成上面的形式 2.泛型委托---Func.Action 3.委托的意义:解耦 4.委托的意义:异步多线程 5.委托的意义:多播委托 6.观察者模 ...

  8. js-权威指南学习笔记17

    第十七章 事件处理 1.事件处理程序或事件监听程序是处理或响应事件的函数. 2.事件对象是与特定事件相关且包含有关该事件详细信息的对象. 3.响应通过键盘改变焦点的表单元素在得到和失去焦点时会分别出发 ...

  9. Linux下汇编语言学习笔记17 ---

    这是17年暑假学习Linux汇编语言的笔记记录,参考书目为清华大学出版社 Jeff Duntemann著 梁晓辉译<汇编语言基于Linux环境>的书,喜欢看原版书的同学可以看<Ass ...

随机推荐

  1. SqlCommand的ExecuteReader方法----转载

    SqlCommand的ExecuteReader方法 原创 小道  2018-08-28 17:32:01  阅读 1353 次 评论 0 条 摘要: 用于执行查询语句,并返回一个DataReader ...

  2. Vue 路由组件

    目录 组件数据局部化处理 路由逻辑跳转 组件传参 父传子 子传父 组件的生命周期钩子 路由传参 全家配置自定义 CSS 与 js 总结: 组件数据局部化处理 不管页面组件还是小组件,都可能会被多次复用 ...

  3. 一、linux基础-对文件操作

    1.1文件夹创建-复制-移动-重命名-删除1.创建文件夹mkdir zjbdir 2.复制文件/文件夹复制文件到:当前目录cp -r zjbdir  zjbdir201600819复制文件到:当前目录 ...

  4. 如何让浏览器的左上角显示自己的logo的小诀窍

    很简单,只需要在head头部加上以下代码 <link rel="icon" href="图片路径" type="image/x-icon&quo ...

  5. Python 100 Days

    Day 1 python的缺点 执行效率稍低,因此计算密集型任务可以由C/C++编写. 在开发时可以选择的框架太多(如Web框架就有100多个),有选择的地方就有错误. python解释器 官方的Py ...

  6. 使用onclick报SyntaxError: identifier starts immediately after numeric literal

    少了‘’ 错误 onclick="onlineWatch(${row.title})" 正确 onclick="onlineWatch('${row.title}')&q ...

  7. 十七 Ajax&校验用户名功能

    Ajax: 即"Asynchronous JavaScript And XML", 异步JavaScript和XML , 是指一种创建的交互式页面应用的网页开发技术,它并不是新的技 ...

  8. 关于页面跳转之后获取不到session数据的问题

    暂时的解决方法有两种,亲测有效: 方法一:  将页面跳转方式由a标签改为请求转发request.getRequestDispatcher("stu_list.jsp").forwa ...

  9. OTF格式

    OTF, OpenType 字体文件. OpenType也叫Type 2字体,是由Microsoft和Adobe公司开发的另外一种字体格式.它也是一种轮廓字体,比TrueType更为强大,最明显的一个 ...

  10. SciPy fftpack(傅里叶变换)

    章节 SciPy 介绍 SciPy 安装 SciPy 基础功能 SciPy 特殊函数 SciPy k均值聚类 SciPy 常量 SciPy fftpack(傅里叶变换) SciPy 积分 SciPy ...