前言

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

正文

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

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. Latex中也能展示动态图?

    技术背景 在学术领域,很多文档是用Latex做的,甚至有很多人用Latex Beamer来做PPT演示文稿.虽然在易用性和美观等角度来说,Latex Beamer很大程度上不如PowerPoint,但 ...

  2. 1.云原生之Docker容器技术基础知识介绍

    转载自:https://www.bilibili.com/read/cv15180540/?from=readlist

  3. 单机部署minio,设置Nginx代理,配置https(TLS)访问

    安装 下载地址:https://dl.min.io/ # 创建目录 mkdir -p /usr/local/minio/{data,bin,etc} # 下载minio wget https://dl ...

  4. 第一章:模型层 - 5:模型的元数据Meta

    模型的元数据,指的是"除了字段外的所有内容",例如排序方式.数据库表名.人类可读的单数或者复数名等等.所有的这些都是非必须的,甚至元数据本身对模型也是非必须的.但是,我要说但是,有 ...

  5. Fluent插件管理

    官方文档地址:https://docs.fluentd.org/deployment/plugin-management 命令fluent-gem是Fluentd用来安装插件的,它是gem命令的包装器 ...

  6. C++自学笔记 初始化列表 Initializer list

    初始化p A(){ p = 0;cout<<"A::A()"<<endl;} 初始化列表 Initializer list A():p(0){ cout&l ...

  7. Docker容器获取宿主机信息

    最近在做产品授权的东西,开始宿主机为Window,程序获取机器硬件信息相对简单些,后来部署时发现各种各样的的环境问题,所有后来改用dokcer部署,docker方式获取宿主机信息时花了些时间,特此记录 ...

  8. 洛谷P1725 琪露诺 (单调队列/堆优化DP)

    显然的DP题..... 对于位置i,它由i-r~i-l的位置转移过来,容易得到方程 dp[i]=dp[i]+max(dp[i−r],...,dp[i−l]). 第一种:n2的暴力,只能拿部分分. 1 ...

  9. Mysql编程中遇到的小错误

    我在mysql中创建的数据库表语句为如下 create table grade (id int not null, name varchar(255), desc varchar(255), prim ...

  10. <三>从编译器角度理解C++代码编译和链接原理

    1代码 点击查看代码 **sum.cpp** int gdata=10; int sum(int a,int b){ return a+b; } **main.cpp** extern int gda ...