重学c#系列——委托和匿名函数[二十五]
前言
简单介绍一下什么是委托。
正文
以前也写过委托,这次算是重新归档,和新的补充吧。
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#系列——委托和匿名函数[二十五]的更多相关文章
- Hadoop MapReduce编程 API入门系列之Crime数据分析(二十五)(未完)
不多说,直接上代码. 一共12列,我们只需提取有用的列:第二列(犯罪类型).第四列(一周的哪一天).第五列(具体时间)和第七列(犯罪场所). 思路分析 基于项目的需求,我们通过以下几步完成: 1.首先 ...
- 3 委托、匿名函数、lambda表达式
委托.匿名函数.lambda表达式 在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法.C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方 ...
- 用委托、匿名函数、Lambda的方式输出符合要求的数
最近看了一些博客,对委托和匿名函数和Lambda的方式有了一些更深的理解,在前人的基础上.我也写3个例子 using System; using System.Collections.Generic; ...
- C#匿名委托,匿名函数,lambda表达式
一.类型.变量.实例之间的关系. 类型>变量>实例 类型可以创建变量,实体类可以创建实例,实例可以存储在变量里. 二.委托使用过程: 1.定义委托(写好签名): 2.创建委托变量: 3.给 ...
- CSharp委托与匿名函数
CSharp委托与匿名函数 场景 面对事件处理,我们通常会通过定义某一个通用接口,在该接口中定义方法,然后在框架代码中,调用实现该接口的类实例的方法来实现函数的回调.可能这样来说有些抽象,那我们提供一 ...
- 重学c#系列——字典(十一)
前言 重学c#系列继续更新,简单看一下字典的源码. 看源码主要是解释一下江湖中的两个传言: 字典foreach 顺序是字典添加的顺序 字典删除元素后,字典顺序将会改变 正文 那么就从实例化开始看起,这 ...
- 面向对象的基本特征:封装(接口 、struct、枚举、委托、匿名函数) 继承,多态。
如何理解面向对象的基本特征:封装 我们通过接口 .struct.枚举.委托.泛型.匿名函数的去理解封装 接口 .struct.枚举.委托.泛型.匿名函数有什么区别?我们通过这些IL探究真相,案例如下: ...
- C#基础系列——委托和设计模式(二)
前言:前篇 C#基础系列——委托实现简单设计模式 简单介绍了下委托的定义及简单用法.这篇打算从设计模式的角度去解析下委托的使用.我们知道使用委托可以实现对象行为(方法)的动态绑定,从而提高设计的灵活性 ...
- 《手把手教你》系列技巧篇(二十五)-java+ selenium自动化测试-FluentWait(详细教程)
1.简介 其实今天介绍也讲解的也是一种等待的方法,有些童鞋或者小伙伴们会问宏哥,这也是一种等待方法,为什么不在上一篇文章中竹筒倒豆子一股脑的全部说完,反而又在这里单独写了一篇.那是因为这个比较重要,所 ...
- 委托,匿名函数和lambda表达式
很早之前就接触到了委托,但是一直对他用的不是太多,主要是本人是菜鸟,能写的比较高级的代码确实不多,但是最近在看MSDN微软的类库的时候,发现了微软的类库好多都用到了委托,于是决定好好的研究研究,加深一 ...
随机推荐
- Windows 11 新材质 Mica Alt 效果展示
本文是 WinUI 3 踩坑记 的一部分,该系列发布于 GitHub@Scighost/WinUI3Keng,若内容出现冲突以 GitHub 上的为准. 微软在 2022-09-02 更新了官方文档, ...
- .NET 7 来了!!!
.NET 7 首个RC(发布候选)版本 最近 .Net 的大事件,就是微软发布了.NET 7的首个RC(发布候选)版本,而据微软发布的消息,这是 .NET 7 的最后一个预览版,下一个版本将是第一个候 ...
- 搭建Elasitc stack集群需要注意的日志问题
文章转载自:https://blog.csdn.net/u013613428/article/details/84943577 {{uploading-image-736853.png(uploadi ...
- MongoDB 副本集的用户和权限一般操作步骤
步骤总结: 在主节点上添加超管用户,副本集会自动同步 按照仲裁者.副本节点.主节点的先后顺序关闭所有节点服务 创建副本集认证的key文件,复制到每个服务所在目录 修改每个服务的配置文件,增加参数 启动 ...
- 在CentOS 8服务器上搭建FastDFS环境
什么是FastDFS? 这里,我就摘录下百度百科上对于FastDFS的描述. FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下 ...
- 第一周python作业
print("hello world") height=float(input("请输入你的身高:")) weight=float(input("请输 ...
- Java程序设计(三)作业
题目1:用户输入学号,如果是以ccutsoft开头,并且后边是4位数字,前两位大于06小于等于当前年份.判断用户输入是否合法.ccutsoft_0801. 1 //题目1:用户输入学号,如果是以abc ...
- aws-s3-国际global与国内CN的一些说明
S3云存储国际版最近经常被墙,国内部分地区有时能正常上传下载,有时也会直接报错网络错误等信息, 所以建议S3使用国内AWS的.国内S3与国外S3在使用时需要注意以下几点: 1)URL不通用 国际版的S ...
- 关于docker创建容器报错-docker: Error response from daemon: runtime "io.containerd.runc.v2" binary not installed
今天在对一台服务器(docker相关的业务服务器)进行OS补丁时,默认使用的 yum update -y 对所有的安装包进行了升级 升级完成后,让应用方检查确认应用及功能是否一切正常,如果不正常,严重 ...
- STM32的SPI口的DMA读写[原创www.cnblogs.com/helesheng]
SPI是我最常用的接口之一,连接管脚仅为4根:在常见的芯片间通信方式中,速度远优于UART.I2C等其他接口.STM32的SPI口的同步时钟最快可到PCLK的二分之一,单个字节或字的通信时间都在us以 ...