首页 > 编程语言 >重学c#系列——委托和匿名函数[二十五]

重学c#系列——委托和匿名函数[二十五]

时间:2022-11-24 17:02:54浏览次数:68  
标签:委托 c# int 匿名 test static 二十五 TestDelegate

前言

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

正文

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

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#,int,匿名,test,static,二十五,TestDelegate
From: https://www.cnblogs.com/aoximin/p/16922423.html

相关文章

  • css的选择器
    /*class选择器*/.s1{width:100;a:linkimg{filter:gray;}a:hoverimg{filter:"";}}/*id选择器的使用*/#id1{background-color:g......
  • java.io.FileNotFoundException:open failed: EACCES (Permission denied)
    在android中创建一个FileOutputStream的时候,报错<spanstyle="font-size:18px;">java.io.FileNotFoundException:/storage/emulated/0/a.jpg:openfailed:EACCES(Permis......
  • 分布式存储之 etcd 的集群管理
    在分布式文件存储中,我们通常会面临集群选主,配置共享和节点状态监控的问题。通过etcd(基于Raft协议))可以实现超大规模集群的管理,以及多节点的服务可靠性。今天,我们就聊聊e......
  • win10家庭版找不到gpedit.msc的解决办法
    (39条消息)win10家庭版找不到gpedit.msc的解决办法(亲测有效)_望穿秋水见伊人的博客-CSDN博客_gpedit.msc找不到最近尝试关机自动删除文件的设置,需要用到“gpedit.msc”,但......
  • win10装centos双系统之后,win10的启动项消失的解决方法
    在网上教程​​http://www.centoscn.com/image-text/setup/2014/0728/3365.html​​的指引下在win10的系统下安装完centos7之后,莫名其妙原来Windows的启动引导消失了......
  • navicat 连接mssqlserver 错误:[IM002] [Microsoft][ODBC驱动程序管理器]未发现数据源
    错误解决安装完成后,下面就是用本机的Navicat来连接SQLserver,这里确实有点麻烦,所以特地来写个博客记录一下当我们想要连接的时候会出现这样的错误[IM002][Microsoft][ODBC......
  • vue2 vue-cli12 vue2项目创建 创建自定义配置 严格模式 超详细的vue2项目创建
    设置全局的cli输入命令:vuei-g@vue/cli快速生成工程化项目:vuecreate项目名create后,选择最后一个自定义选择 第一个必选第二个是TS第三个是渐进式框架......
  • centos双系统恢复windows启动项
    在网上教程​​http://www.centoscn.com/image-text/setup/2014/0728/3365.html​​的指引下在win10的系统下安装完centos7之后,莫名其妙原来Windows的启动引导消失了......
  • c# mutex monitor
    什么是Mutex“mutex”是术语“互相排斥(mutuallyexclusive)”的简写形式,也就是互斥量。互斥量跟临界区中提到的Monitor很相似,只有拥有互斥对象的线程才具有访问资源的......
  • mac命令大全
    Mac终端命令大全OSX的文件系统OSX采用的Unix文件系统,所有文件都挂在跟目录/下面,所以不在要有Windows下的盘符概念。你在桌面上看到的硬盘都挂在/Volumes下。比......