1.什么是委托

委托是C#中一种类型,它的作用相当于C语言中的函数指针,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用if-else(Switch)语句,同时使得程序具有更好的可扩展性。

       委托和类是同级别的,我们可以直接将delegate看成为关键字class,区别为class里存放的是一系列方法,属性,字段,事件,索引。而delegate里存放的是一系列具有相同类型参数和返回回类型的方法的地址的地址。可以看着为储存方法的载体。

2.声明委托

delegate <函数返回类型> 委托名(函数参数)

例:public delegate void MyDelegate(string name);

3.实例化委托

(1) 常规实例化委托

语法:<委托名> 实例化名 = new <委托名>(注册函数)

注意:注册函数不包含参数,或者可以直接将一个注册函数赋值给委托。 例:

MyDelegate  _md = new MyDelegate(method);

(2)匿名方法实例化委托

语法: <委托类型> <实例化名>=delegate(<函数参数>){函数体}; 例:

 MyDelegate  md = delegate(string s)
{
Console.WriteLine(s);
};

(3)使用Lambda表达式实例化委托

语法:参数列 =>语句或语句块

用法规则:

  1. “Lambda表达式”的参数数量必须和“委托”的参数数量相同;
  2. 如果“委托”的参数中包括有ref或out修饰符,则“Lambda表达式”的参数列中也必须包括有修饰符;     例:
 class Test
{
public delegate void MyDelegate(out int x);//声明委托
static void Print(MyDelegate test)
{
int i;
test(out i);
Console.Write(i);
}
static void Main()
{
Print((out int x) => x = 3);
Console.Read();
}
}

这三种方法都可以实现功能,lamda表达式只是简化了委托的声明,以及委托的实例化和调用。 从下面的例子中让我们看看三者的区别:

class Program
{
//声明委托
delegate int MyDelegate(int x, int y);
static void Main(string[] args)
{
//实例化委托
//1、使用new关键字
MyDelegate _md = new MyDelegate(Sum);
//2、使用匿名方法
MyDelegate md= delegate(int x, int y)
{
return x + y;
};
//3、使用Lambda表达式
MyDelegate mdLambda = (int x, int y) => { return x + y; };
}
static int Sum(int x, int y)
{
return x + y;
}
}

4.多播委托

多播委托继承自 Delegate,即 “多路广播委托”(MulticastDelegate)。从名字就可以看出,此种委托可以像广播一样将影响信息“传播”到四面八方。多播委托类拥有一个方法调用列表,调用委托时,它就会逐一调用该列表中的方法,从而实现多重影响。

       在现实生活中,多播委托的例子是随处可见的,例如某点餐的应用程序,既可以预定普通的餐饮也可以预定蛋糕、鲜花、水果等商品。在这里委托相当于点餐平台,每一个类型的商品可以理解为在委托上注册的一个方法。

4.1 多播委托的实例化

多播委托的初始化可以像普通委托一样,传入一个签名相同的实例方法。同时,多播委托重载了 += 运算符和 -= 运算符,用来向其调用列表中添加或者删除方法。调用多播委托时,方法将按照添加的顺序被依次调用。

我们定义一个简单的执行加减运算的委托,并利用+=运算符和Lambda表达式为该多播委托添加两个方法:

public delegate int AddDelegate(int a);
AddDelegate md = new AddDelegate(i => i + 10);
md += i => i - 10;

4.2 多播委托的调用与返回结果

!!!使用委托,直接md( )就相当于使用了md. Invoke()

调用上面的AddDelegate,传入一个参数10:

Console.WriteLine(md(10));

运行代码,得到结果:

0

你们有疑问吗?为什么有两个方法,怎么只有一个返回值呢?

        实际上,两个方法都被调用了。案例讲解:

        多播委托按照顺序调用其列表中的方法。首先,参数先调用了 i => i + 10 函数,得到了函数返回值20。然而,委托的调用并没有停止, 而是继续调用剩余的方法。然后继续对参数调用 i => i - 10 函数,得到新的返回值0,上个函数的返回值被覆盖。至此委托调用结束,返回最后调用方法的返回结果。

        因此,一个有非空返回值的多播委托通常是没有意义的,因为只能获得最后一个方法的返回结果。所以通常,多播委托的返回类型为 void。

4.3 多播委托的逐个调用

那么对于返回类型不为空的多播委托来说,有没有办法得到所有方法的返回结果呢?答案是有,多播委托提供了一个 GetInvocationList () 方法,通过它可按顺序获取并执行调用列表中的方法。用法举例:

Console.WriteLine("每个都调用:");
foreach (AddDelegate f in md.GetInvocationList())
Console.WriteLine(f.Invoke(10));

如此便可逐个得到方法的输出结果:

每个都调用:
20
0

5. 泛型委托

5.1 泛型委托原型

委托也支持泛型的使用 ,泛型委托原型:delegate <委托名><T1,T2,T3...> (T1 t1,T2 t2,T3 t3...)

5.2 内置泛型委托

Func委托

       Func委托代表着拥有返回值的泛型委托。Func有一系列的重载,形式如 Func<T1,T2, ... TResult>,其中TResult代表委托的返回值类型,其余均是参数类型。只有一个T时,即Func,代表该委托是无参数的。.NET封装了最多16个输入参数的Funct<>委托。

       !!!若方法返回 void ,由于 void 不是数据类型,因此不能定义Func委托。

Action委托

       Action委托代表返回值为空 void 的委托,它也有一些列重载,最多拥有16个输入参数。用法与Func相同。

Predicate委托

       这个一般用的较少,它封装返回值为bool类型的委托,可被Func代替。

6.委托的用处

说白了,委托就是第三方,调用者告诉第三方要做什么,然后调用者就不用管了 这个委托(第三方)就会去调用方法去帮你实现。

使用委托的好处:

       1.相当于用方法作为另一方法参数(类似于C的函数指针)

       2.在两个不能直接调用的方法中作为桥梁,如:在多线程中的跨线程的方法调用就得用委托。

       3.当不知道方法具体实现什么时使用委托,如:事件中使用委托。

C#委托的详细总结的更多相关文章

  1. C#委托的详细使用

    代码如下: public delegate void GreetingDelegate(string name);//定义委托,它定义了可以代表方法的类型 class Program { public ...

  2. C# 从CIL代码了解委托,匿名方法,Lambda 表达式和闭包本质

    前言 C# 3.0 引入了 Lambda 表达式,程序员们很快就开始习惯并爱上这种简洁并极具表达力的函数式编程特性. 本着知其然,还要知其所以然的学习态度,笔者不禁想到了几个问题. (1)匿名函数(匿 ...

  3. 理解js事件冒泡事件委托事件捕获

    js事件冒泡 javascript的事件传播过程中,当事件在一个元素上出发之后,事件会逐级传播给先辈元素,直到document为止,有的浏览器可能到window为止,这就是事件冒泡现象. <di ...

  4. UE4技术总结——委托

    UE4技术总结--委托 目录 UE4技术总结--委托 一.定义 二.用法 2.1 声明与调用委托 2.1.1 单播委托 2.1.1.a 声明 2.1.1.b 绑定 2.1.1.c 执行委托 2.1.1 ...

  5. C#由变量捕获引起对闭包的思考

    前言 偶尔翻翻书籍看看原理性的东西确实有点枯燥,之前有看到园中有位园友说到3-6年工作经验的人应该了解的.NET知识,其中就有一点是关于C#中的闭包,其实早之前在看书时(之前根本不知道C#中还有闭包这 ...

  6. [知识库分享系列] 二、.NET(ASP.NET)

    最近时间又有了新的想法,当我用新的眼光在整理一些很老的知识库时,发现很多东西都已经过时,或者是很基础很零碎的知识点.如果分享出去大家不看倒好,更担心的是会误人子弟,但为了保证此系列的完整,还是选择分享 ...

  7. C#由变量捕获引起对闭包

    C#由变量捕获引起对闭包的思考   前言 偶尔翻翻书籍看看原理性的东西确实有点枯燥,之前有看到园中有位园友说到3-6年工作经验的人应该了解的.NET知识,其中就有一点是关于C#中的闭包,其实早之前在看 ...

  8. CLR类型设计之泛型(二)

    在上一篇文章中,介绍了什么是泛型,以及泛型和非泛型的区别,这篇文章主要讲一些泛型的高级用法,泛型方法,泛型接口和泛型委托,协变和逆变泛型类型参数和约束性,泛型的高级用法在平时的业务中用的不多,多用于封 ...

  9. C# 与 Java 的一些差异

    如果你是 Java 开发人员,则可以在 Xamarin 平台上充分利用你的技能和现有代码,同时获得 C# 的代码重用优势.你会发现 C# 语法与 Java 语法非常相似,这两种语言提供非常类似的功能. ...

随机推荐

  1. package wang/test is not in GOROOT (/usr/local/go/src/wang/test)

    如果要用 gopath模式 引入包 从src目录下开始引入 需要关闭 go mod 模式 export GO111MODULE=off 如果使用go mod 模式 export GO111MODULE ...

  2. centos8安装sersync为rsync实现实时同步

    一,查看本地centos的版本: [root@localhost lib]# cat /etc/redhat-release CentOS Linux release 8.1.1911 (Core) ...

  3. centos8平台安装ansible2.9

    一,ansible的用途: ansible是基于python开发的自动化运维工具, 它基于SSH远程连接服务, 可以实现批量系统配置.批量软件部署.批量文件拷贝.批量运行命令等多个运维功能 因为基于s ...

  4. requests-html添加header

    from requests_html import HTMLSession session = HTMLSession() headers = { "User-Agent":&qu ...

  5. 构建调试Linux内核网络的环境Menuos系统

    一.Linux内核源码下载 下载网址为:https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.1.tar.xz 下载完成后放入home/Menu ...

  6. kubernetes教程第一章-kubeadm高可用安装k8s集群

    目录 Kubeadm高可用安装k8s集群 kubeadm高可用安装1.18基本说明 k8s高可用架构解析 kubeadm基本环境配置 kubeadm基本组件安装 kubeadm集群初始化 高可用Mas ...

  7. Linux入门到放弃之六《磁盘和文件系统管理二》

    上一篇博客写到了如何创建卷组和创建逻辑卷,但是有一个问题,需要更大逻辑卷空间怎么办呢? 要求:使用lvextend命令为逻辑卷 mail扩充容量,从卷组 mail_store 上再 划出5GB给逻辑卷 ...

  8. php7.1安装openssl扩展

    1,进入到PHP源码目录中的ext中的openssl目录 2,phpize 3,./configure --with-openssl --with-php-config=/usr/local/php/ ...

  9. Serializable使用

    android的另一个序列化Serializable比较简单,实现它的接口,然后生成所有成员变量的方法,再生成所有成员变量的getset方法,serializable可以存储对象,所以下面代码传递了一 ...

  10. es6 新的数组操作

    ES6数组新增的几个方法 2017年03月24日 13:38:04 tang15886395749 阅读数:10461 标签: ES6数组新增方法 更多 个人分类: js相关   关于数组中forEa ...