前言

简单介绍一下什么是委托。

正文

以前也写过委托,这次算是重新归档,和新的补充吧。

https://www.cnblogs.com/aoximin/p/13940125.html

有些人说委托是函数指针的包装,也有些人说委托是一个方法或多个方法的引用。

这都是没有问题,委托是一个概念,微软官方文档说委托是一种引用类型,表示对具有特定参数列表和返回类型的方法引用。

我觉得太啰嗦了,实际上就是方法的引用。

上面都是委托的概念,但是实现方式每种语言可能都不一样。

比如c++ 和 c 用的是函数指针,而c# 用的是生成包装类(等下IL),当然本质还是函数指针。

那么来看下委托。

internal class Program
{
delegate int TestDelegate(int a); static void Main(string[] args)
{
TestDelegate a = test;
a(0);
} public static int test(int a)
{
return 0;
}
}

将test 给了委托a,然后调用的时候直接a()就可以了。

用起来十分简单。

实际上对IL来说其实是没有委托这个概念的,通过反编译来看下原理。

private static void Main(string[] args)
{
TestDelegate a = new TestDelegate(test);
a(0);
}

实际上会生成TestDelegate这样一个类,然后将test 引用添加进去。

来看下il。

再看下TestDelegate是一个什么样的类。

就是把调用的object 和 方法的引用放入包装类中了,然后invoke 可以进行调用。

如果是多个方法的引用呢?

internal class Program
{
delegate int TestDelegate(int a); static void Main(string[] args)
{
TestDelegate a = test;
a += test;
a(0);
} public static int test(int a)
{
return 0;
}
}

看下IL:

原理就是又new了一个TestDelegate,然后用Delegate 将两个相连。

Combine 是一个静态方法哈。

本质是调用a的combineImp这个方法。之所以有这个一个静态方法是为了避免出现a为空的情况,如果a为空,直接把b给a啊。

这个是我们写链式结构可以学习的,这样就不用判断声明的时候是否为空。

然后c# 帮我们提取定义了很多委托,以至于我们几乎不用去声明委托。

比如Func 和 Action,Func 有返回值,Action没有。

下面介绍匿名函数,匿名函数有两个要介绍的,他们分别是匿名方法和lambda表达式。

他们原理都一样,都是生成匿名函数,只是写法不一样。

delegate int TestDelegate(int a);

static void Main(string[] args)
{
TestDelegate a = delegate (int a)
{
return 0;
};
}

看下反编译后的内容。

private static void Main(string[] args)
{
TestDelegate a = <>c.<>9__1_0 ?? (<>c.<>9__1_0 = new TestDelegate(<>c.<>9.<Main>b__1_0));
}

那么看下<>c 这个类:

首先看到第一个框,那么作者的意思是想把 <>c做成一个单例。

里面有委托的引用。然后下面这个

b__1_0 就是生成的方法。

其实匿名方法还是编译帮忙生成对应的方法名。

如果用lambda 表达式写的话,那么是这样写的:

这种写法编译出来的代码一模一样。只是不同写法的问题。

值得注意的是匿名函数如果引用了外部的信息,那么会形成闭包。

比如说:

static void Main(string[] args)
{
Student s = new Student();
TestDelegate a = (a) => {
s = null; return 0;
}; a += (b) => {
return 0;
}; a += (c) => {
return 0;
};
}

首先b和c(第二个和第三个匿名)没有引用外部对象,那么都会生成在<>c这个类中。

第一个有外部引用生成了另外一个类。

然后实例化<>c__DisplayClass1_0后,那么会将s赋值进来。

所以会形成这种闭包,这是值得注意的地方。

下一节委托的发布订阅与事件。

重学c#系列——委托和匿名函数[二十五]的更多相关文章

  1. Hadoop MapReduce编程 API入门系列之Crime数据分析(二十五)(未完)

    不多说,直接上代码. 一共12列,我们只需提取有用的列:第二列(犯罪类型).第四列(一周的哪一天).第五列(具体时间)和第七列(犯罪场所). 思路分析 基于项目的需求,我们通过以下几步完成: 1.首先 ...

  2. 3 委托、匿名函数、lambda表达式

    委托.匿名函数.lambda表达式 在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法.C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方 ...

  3. 用委托、匿名函数、Lambda的方式输出符合要求的数

    最近看了一些博客,对委托和匿名函数和Lambda的方式有了一些更深的理解,在前人的基础上.我也写3个例子 using System; using System.Collections.Generic; ...

  4. C#匿名委托,匿名函数,lambda表达式

    一.类型.变量.实例之间的关系. 类型>变量>实例 类型可以创建变量,实体类可以创建实例,实例可以存储在变量里. 二.委托使用过程: 1.定义委托(写好签名): 2.创建委托变量: 3.给 ...

  5. CSharp委托与匿名函数

    CSharp委托与匿名函数 场景 面对事件处理,我们通常会通过定义某一个通用接口,在该接口中定义方法,然后在框架代码中,调用实现该接口的类实例的方法来实现函数的回调.可能这样来说有些抽象,那我们提供一 ...

  6. 重学c#系列——字典(十一)

    前言 重学c#系列继续更新,简单看一下字典的源码. 看源码主要是解释一下江湖中的两个传言: 字典foreach 顺序是字典添加的顺序 字典删除元素后,字典顺序将会改变 正文 那么就从实例化开始看起,这 ...

  7. 面向对象的基本特征:封装(接口 、struct、枚举、委托、匿名函数) 继承,多态。

    如何理解面向对象的基本特征:封装 我们通过接口 .struct.枚举.委托.泛型.匿名函数的去理解封装 接口 .struct.枚举.委托.泛型.匿名函数有什么区别?我们通过这些IL探究真相,案例如下: ...

  8. C#基础系列——委托和设计模式(二)

    前言:前篇 C#基础系列——委托实现简单设计模式 简单介绍了下委托的定义及简单用法.这篇打算从设计模式的角度去解析下委托的使用.我们知道使用委托可以实现对象行为(方法)的动态绑定,从而提高设计的灵活性 ...

  9. 《手把手教你》系列技巧篇(二十五)-java+ selenium自动化测试-FluentWait(详细教程)

    1.简介 其实今天介绍也讲解的也是一种等待的方法,有些童鞋或者小伙伴们会问宏哥,这也是一种等待方法,为什么不在上一篇文章中竹筒倒豆子一股脑的全部说完,反而又在这里单独写了一篇.那是因为这个比较重要,所 ...

  10. 委托,匿名函数和lambda表达式

    很早之前就接触到了委托,但是一直对他用的不是太多,主要是本人是菜鸟,能写的比较高级的代码确实不多,但是最近在看MSDN微软的类库的时候,发现了微软的类库好多都用到了委托,于是决定好好的研究研究,加深一 ...

随机推荐

  1. 聊聊两个Go即将过时的GC优化策略

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 这篇文章本来是要讲 Go Memory Ballast 以及 Go GC Tuner 来 ...

  2. [Python]-tqdm模块-给for循环加上进度条

    import tqdm 使用tqdm模块,可以在漫长的for循环加上一个进度条,显示当前进度百分比. 将tqdm写在迭代器之外即可:tqdm(iterator) for i in tqdm(range ...

  3. [C/C++]C语言-踩坑记录

    很久没写C语言的代码,发现很多小细节,记下来备查. 0. C语言常规头文件 #include <stdlib.h> #include <stdio.h> 1. 二维数组的开辟和 ...

  4. 第四周(实际是n+周)

    1. tomcat启动报错 报错内容:ERROR RUNNING 'TOMCAT': UNABLE TO OPEN DEBUGGER PORT (127.0.0.1:38667): JAVA.NET. ...

  5. kibana访问多个 Elasticsearch 节点间的负载均衡

    如果 Elasticsearch 集群有多个节点,分发 Kibana 节点之间请求的最简单的方法就是在 Kibana 机器上运行一个 Elasticsearch 协调(Coordinating onl ...

  6. 使用读写分离模式扩展 Grafana Loki

    转载自:https://mp.weixin.qq.com/s?__biz=MzU4MjQ0MTU4Ng==&mid=2247500127&idx=1&sn=995987d558 ...

  7. MySQL学习(2)---MySQL数据类型

    ps:此随笔基于mysql 5.7.*版本. 补充: UNSIGNED:所有整数类型都可以有一个可选(非标准)UNSIGNED属性.无符号类型可用于在列中仅允许非负数存在,或者当开发者需要该列的较大数 ...

  8. python运行以及入门语法基础

    pycharm下载与使用 1.pycharm官网下载(直接到pycharm下载地址) http://www.jetbrains.com/pycharm/download/#section=window ...

  9. img通过修改css等比例缩小图片

    css中加上:object-fit:cover 例子: img{ width: 200px; height: 400px; object-fit: cover; }

  10. day09-1存储引擎

    存储引擎 1.基本介绍 基本介绍 MySQL的表类型由存储引擎(Storage Engines)决定,主要包括MyISAM.innoDB.Memory等 MySQL数据表主要支持六种类型,分别是:CS ...