重学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做成一个单例。
里面有委托的引用。然后下面这个
其实匿名方法还是编译帮忙生成对应的方法名。
如果用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#数组赋初值_C#数组初始化
- C# Volatile
- C#使用匿名函数解决EventHandler参数传递的难题
- asp.net(c#)获取内容第一张图片地址的函数
- C#版的Escape()和Unescape()函数分享
- c#中虚函数的相关使用方法
- C#泛型类(函数)的实例化小例子
- 基于C#中可以new一个接口?的问题分析
- c#自定义泛型类的实现
- c#之利用API函数实现动画窗体的方法详解
- C#操作config文件的具体方法
- 解析c#操作excel后关闭excel.exe的方法
- javaScript函数中执行C#代码中的函数方法总结
- c#代码自动修改解决方案下任意文件实例
- c#获取季度时间实例代码(季度的第一天)
- c#DateTime常用操作实例(datetime计算时间差)
- C#函数式程序设计之用闭包封装数据的实现代码
- C#适用于like语句的SQL格式化函数
- C#中使用HttpDownLoadHelper下载文件实例
- C#动态执行批处理命令的方法
- C#基于数据库存储过程的AJAX分页实例
- C#函数式编程中的递归调用之尾递归详解
- C#函数式编程中的标准高阶函数详解
- C#属性(Attribute)用法实例解析