[C#基础] 委托
什么是委托
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
使用委托可以将多个方法绑定到同一个委托变量,当调用此变量时(这里用“调用”这个词,是因为此变量代表一个方法),可以依次调用所有绑定的方法。
委托的定义
通常一个委托被定义为
- public delegate void CalcDelegate(int x, int y);
关键字delegate用来声明一个委托类型CalcDelegate,可以对其添加访问修饰符,默认返回类型为void,接受两个int型参数x和y,但是委托并不等于方法,而是一个引用类型。
下面介绍如何通过委托来实现一个计算器模拟程序。
- //声明一个委托
- public delegate void CalcDelegate(int x, int y);
- //创建与委托关联的方法,两者具有相同的返回值类型和参数列表
- public static void Add(int x, int y)
- {
- Console.WriteLine(x+y);
- }
- //定义委托类型变量
- private static CalcDelegate MyDelegate;
- static void Main(string[] args)
- {
- //进行委托绑定
- MyDelegate = new CalcDelegate(Add);
- //回调Add方法
- MyDelegate(, );
- }
上述示例,在类内部声明了一个CalcDelegate委托类型,它具有和关联方法Add完全相同的返回值类型和参数列表,否则将导致编译错误。将方法Add传递给CalcDelegate构造器,也就是将方法Add指派给CalcDelegate委托,并将该引用赋给MyDelegate变量,也就表示MyDelegate变量保存了指向Add方法的引用,以此实现对Add 的回调。
由此可见,委托表示了对其回调方法的签名,可以将方法当做参数进行传递,并根据传入的方法来动态改变方法的调用。只要为委托提供相同签名的方法,就可以与委托绑定。
例如:
- public static void Subtract(int x, int y)
- {
- Console.WriteLine(x - y);
- }
- static void Main(string[] args)
- {
- //进行委托绑定
- MyDelegate = new CalcDelegate(Subtract);
- //回调Add方法
- MyDelegate(, );
- }
多播委托和委托链
在上述委托实现中,Add方法和Subtract方法可以绑定与同一个委托类型MyDelegate,由此可以想到将多个方法绑定到一个委托变量,在调用一个方法时,可依次执行其绑定的所有方法,这称为多播委托。
在.NET 中 以 += 和 -= 操作符分别进行绑定和解除绑定的操作,多个方法绑定到一个委托变量就形成了一个委托链,对其调用时将会依次调用所有绑定的回调方法。
例如:
- static void Main(string[] args)
- {
- //进行委托绑定
- MyDelegate = new CalcDelegate(Add);
- MyDelegate += new CalcDelegate(Subtract);
- //回调方法
- MyDelegate(, );
- }
上述执行将在控制台依次输出 3和-1,可见多播委托按照委托链顺序调用所有绑定的方法,同样以 -=操作可以解除委托链上的绑定。
事实上, +=和-=分别调用了 Delegate.Combine和 Delegate.Remove方法
所以上述示例等效于:
- static void Main(string[] args)
- {
- //进行委托绑定
- MyDelegate = (CalcDelegate)Delegate.Combine(new CalcDelegate(Add), new CalcDelegate(Subtract));
- MyDelegate(, );
- }
另外多播委托返回值一般为void值,委托类型为非void类型时,多播委托将返回最后一个调用方法的执行结果,所以在实际应用中不被推荐!
委托的本质
委托在本质上仍然是一个类
该类继承自System.MulticastDelegate类,该类维护一个带有链接的委托列表,在调用多播委托时,将按照委托列表顺序而调用的。还包括一个接受两个参数的构造函数,和三个重要方法 BeginInvoke,EndInvoke和Invoke
在IL代码中可见,首先通过构造函数来创建一个MyDelegate实例,然后通过CalcDelegate::Invoke 执行回调方法调用,可见真正执行调用的是Invoke 方法。因此,也可以通过Invoke 在代码中显示调用。
- MyDelegate.Invoke(, );
匿名方法
匿名方法以内联方式放入委托对象的使用位置,而避免创建一个委托来关联回调方法,也就是由委托调用了匿名的方法
下述示例用匿名方法的方式来实现上述的示例
- CalcDelegate myAddDelegate = delegate(int x, int y)
- {
- Console.WriteLine(x + y);
- };
- CalcDelegate mySubstractDelegate = delegate(int x, int y)
- {
- Console.WriteLine(x - y);
- };
- myAddDelegate(, );
- mySubstractDelegate(, );
事实上匿名方法和委托在IL上是等效的,编译器为匿名方法两个静态成员和静态方法
Lambda表达式
C#3.0引入了Lambda表达式,简化了匿名方法的语法。 我们很容易通过如下步骤把匿名方法转换为lambda表达式。
- 删除delegate关键字
- 在参数列表和匿名方法主体之间放lambda运算符 =>
下述示例演示了lambda表达式
- CalcDelegate myAddDelegate = (int x, int y) =>
- {
- Console.WriteLine(x + y);
- };
- CalcDelegate mySubstractDelegate =(int x, int y)=>
- {
- Console.WriteLine(x - y);
- };
编译器通过推断,允许我们更进一步简化lambda表达式
- 编译器可以从委托的声明中知道委托类型的参数,因此lambda允许我们省略类型参数
- 如果只有一个隐式类型参数,可以省略圆括号
- 如果语句块包含一个返回语句,可以将语句块替换为return关键字后的表达式
有关lambda参数列表的要点如下
- lambda表达式参数列表的参数必须在参数数量,类型和位置上与委托相匹配
- 表达式的参数列表中的参数不一定需要包含类型,除非委托有ref或out参数
- 如果只有一个参数,并且是隐式参数,圆括号可以省略
- 如果没有参数,必须使用空的圆括号()
[C#基础] 委托的更多相关文章
- C#基础委托回顾
C#基础委托回顾 前言 快忘记了. 委托的特点 委托类似于 C++ 函数指针,但它们是类型安全的. 委托允许将方法作为参数进行传递. 委托可用于定义回调方法. 委托可以链接在一起:例如,可以对一个事件 ...
- C#基础---委托的使用
一:什么是委托 委托是一种定义方法签名的类型当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联.您可以通过委托实例调用方法.委托是一个引用类型,所以它具有引用类型所具有的通性.它保存 ...
- c#核心基础-委托
委托是一个类型.C#中的委托是面向对象的,并且它是类型安全的 当创建委托实例的时候,创建的实例会包含一个调用列表,在调用列表中可以包含多个方法.每个方法称作一个调用实体.调用实体可以是静态方法,也可以 ...
- C#基础-委托与事件
委托 delegate是申明委托的关键字 返回类型都是相同的,并且参数类型个数都相同 委托声明 delegate double DelOperater(double num1, double num2 ...
- SQL数据库基础————委托
委托:也称为代理,事件也是一种委托:定义在类的最外面 1.定义委托关键字:delegate函数签名:签名和函数保持一致定义委托的时候要根据函数来定义public delegate int First( ...
- C# 基础 - 委托、事件
1. 委托 sequenceDiagram 方法->>委托: 返回值和入参一样 委托->>方法: 调用委托就是调用绑定的方法 delegate int NumTest(int ...
- C#委托基础
转载自 http://woshixy.blog.51cto.com/5637578/1070976 C#委托基础1——委托基础 委托和其委托的方法必须具有相同的签名.签名相同:1.参数类型 ...
- C#基础---事件的使用
一:什么是事件 事件是可以被控件识别的操作,如按下确定按钮,选择某个单选按钮或者复选框.每一种控件有自己可以识别的事件,如窗体的加载.单击.双击等事件,编辑框(文本框)的文本改变事件,等等.事 ...
- .net基础系列
这里汇总了.net基础的相关文章,方便查阅! .net基础 委托(1)认识委托 委托(2).net 1.x中的委托 委托(3).net 2.0中的委托 委托(4).net 3.5中的委托 委托(5)委 ...
随机推荐
- android ADT 设置编辑字体
新配置的android ADT 设置编辑字体的时候 可能里面没有我们想要的Courier new 这种舒服的字体 那么就在 字体选项窗口的 做下端 有个显示更多字体的链接 然后就显示微软的所有字 ...
- ADO.NET 对象 结构图
- Linux安装完Tomcat后无法登陆管理界面
今天在Linux中安装完Tomcat后无法登陆Tomcat的管理界面,也就无法利用Tomcat管理界面来部署项目. 在Windows中一般配置完Tomcat后,只要在[conf]目录下的“tomcat ...
- 深入理解 Spring 事务原理【转】
本文转自码农网 – 吴极心原创 连接地址:http://www.codeceo.com/article/spring-transactions.html 一.事务的基本原理 Spring事务的本质其 ...
- c语言: Standard C 语言标准函数库
Standard C 语言标准函数库速查 (Cheat Sheet) http://ganquan.info/standard-c/ c语言标准头: <assert.h> 断言 <c ...
- 开发板和centos服务器tftp传文件
CentOS下使用TFTP向目标板传送文件http://www.linuxidc.com/Linux/2010-10/29218.htm 1.安装相关软件包 为了使主机支持TFTP,必须确保TFTP后 ...
- Swift - 手机摇晃的监测和响应
摇晃手机也是一种常用的交互手段(比如微信摇一摇功能).iOS SDK中已经将shake事件方便地融合进去了,就像触发touch事件一样简单,发生摇晃事件后程序会自动执行. 1 2 3 4 5 6 7 ...
- java对象占用内存大小计算方式
案例一: User public class User { } UserSizeTest public class UserSizeTest { static final Runtime runTim ...
- linux命令: sort
参考 linux sort 命令详解 http://www.cnblogs.com/51linux/archive/2012/05/23/2515299.html 1 sort的工作原理 sort将文 ...
- 编译mapnik(win7 环境下vs2008编译mapnik 0.7.1 成功)
编译mapnik(win7 环境下vs2008编译mapnik 0.7.1 成功) ------by wangsh 2012.02.22 Mapnik 是一个开源的 Python/C++ 地图渲染引 ...