前言

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

正文

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

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. B树-删除

    B树系列文章 1. B树-介绍 2. B树-查找 3. B树-插入 4. B树-删除 删除 根据B树的以下两个特性 每一个非叶子结点(除根结点)最少有 ⌈m/2⌉ 个子结点 有k个子结点的非叶子结点拥 ...

  2. 跟羽夏学 Ghidra ——数据

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...

  3. .NET 实现启动时重定向程序运行路径及 Windows 服务运行模式部署

    日常工作中有时候会遇到需要将程序直接在服务器上运行,而不依赖于 IIS 托管的情况,直接运行有两种方式,一种是部署为 服务模式,另一种则是 直接启动 .NET 发布之后的 exe 文件以 控制台模式运 ...

  4. 基于.NET6的简单三层管理系统

    前言 笔者前段时间搬砖的时候,有了一个偷懒的想法:如果开发的时候,简单的CURD可以由代码生成器完成,相应的实体.服务都不需要再做额外的注册,这样开发人员可以省了很多事. 于是就开了这个项目,期望实现 ...

  5. 使用kubeoperator安装的k8s集群配置Ingress规则有关说明

    单独创建一个nginx 在 Deployment 里创建一个nginx工作负载,镜像用:nginx:alpine,并配置service为ClusterIP,然后添加Ingress规则 本地主机host ...

  6. ProxySQL 读写分离方法

    转载自:https://www.jianshu.com/p/597b840bf70c (使用正则表达式实现基本的读/写分离) 在这一部分,我将通过一个示例来演示如何通过正则表达式来实现读/写分离. 首 ...

  7. 安装MySQL8 工具集

    下载地址:https://downloads.mysql.com/archives/utilities/ # wget https://downloads.mysql.com/archives/get ...

  8. #css#如何使用hover,实现父对子的样式改变?

    思路及做法: 鼠标移动到父盒子的时候, 里面所有的子盒子的样式都发生变化的, 只需要直接在hover后面加上空格, 并且加上子盒子的类名 ,里面再写其他样式 .父盒子的类名:hover .子盒子的类名 ...

  9. 关于vmware虚拟机的ova/ovf转换成aws上的AMI镜像

    很多时候,我们会有这样的需求,需要将DC中vmware虚拟化的服务器,迁移到aws上,我们就得先将vmware虚拟机导出,然后转换 关于vmvare虚拟的导出备份,一般有ova(Open Virtua ...

  10. JavaScript函数式编程之函子

    函子(Functor) 函子是一个特殊的容器,通过一个普通对象来实现,该对象具有map方法,map方法可以运行一个函数对值进行处理(变形关系),容器包含值和值变形关系(这个变形关系就是函数).函数式编 ...