C#深入浅出 C#语法中的重中之重——委托(四)
入行半年多了,委托干什么用的还不知道,真心说不过去了,关键对这东西有点恐惧,主要是被老师吓的,记得我C#专业课老师在讲到委托时,原话是这样的,同学们,委托这个地方是难点,暂时不讲,讲了你也不懂,等你有了一定的编程经验,你自会明白。好吧,我懂了,只可意会不可言传。其实,它并没有想象中这么恐怖,只不过我被吓着了,向来就胆小,不敢挑战有点难度的东西,只能玩玩表面的东西,嗨,不废话了,但是这是按照博客园惯例来的,一开始不能太专业,专业了就不是“面向对象”了。
好吧,先提个问题,委托到底是什么?这是个头脑风暴,那家可以随便想.......是类型?是方法?还是是对象? 大家有没有说说你的见解的,大多数教程里更愿意把它叫做代理,叫做方法的指针,好吧,又专业了。其实我认为,这几种的叫法都合适。那它到底是什么?有什么用?为了让不懂编程的人也能看懂我写的东西,我举个实际生活中的例子,比如,二狗,我今天有点事,孩子放学回家没人做饭,我今天就把他暂时交给你照顾了,好吗?那这里做饭这件事其实就是C#中的方法,一个事件的处理过程,二狗就是你的委托人,本来你是孩子的监护人,你理应直接照顾孩子的吃饭上学等等,但是今天特殊情况,自己实在做不了,你就把这事暂时委托给你的朋友,让他帮一下吗。相信大家懂了吗,有没有稍微懂,稍微懂就够了,我们可以跳到C#里来,重新讲述一下委托这个概念,C#中,你本可以直接操作方法,你是方法的创造者(自定义方法),或者,C#为你做好的方法(类库里的方法),但是我把方法委托给别人来做,但是这个人要有和我一样的能耐(可以为理解方法签名要一致)才能帮我完成方法的调用。
补充方法签名的概念,方法签名指方法名称、参数个数、参数类型、方法参数的顺序。与方法返回值无关。方法签名也成为方法标识。
TIP:"在方法重载的上下文中,方法的签名不包括返回值。 但在委托的上下文中,签名包括返回值。 换句话说,方法和委托必须具有相同的返回类型。"来自MSDN
接下来我们按照委托如何定义,如何使用,为什么要使用委托几个角度学习它。并与C语言中函数指针类比学习。
以实现四则计算器为目的,首先定义加、减、乘、除四个计算方法,在主函数中使用委托的方式进行调用。
class Program
{
delegate int MathDelegate(int i, int j);//delegate 和 Delegate 的区别是什么
static int Add(int i,int j)
{
return i+j;
}
static int Subtract(int i,int j)
{
return i - j;
}
static int multiply(int i,int j)
{
return i * j;
}
static int devide(int i,int j)
{
return i / j;
}
static void Main(string[] args)
{
MathDelegate myDelegate = new MathDelegate(Add);
int result=myDelegate(,);
Console.WriteLine("加法结果是:{0}",result); myDelegate = new MathDelegate(Subtract);
result = myDelegate(, );
Console.WriteLine("减法结果是:{0}", result); myDelegate = new MathDelegate(multiply);
result = myDelegate(, );
Console.WriteLine("乘法结果是:{0}", result); myDelegate = new MathDelegate(devide);
result = myDelegate(, );
Console.WriteLine("除法结果是:{0}", result); Console.ReadKey();
}
}
如同i可以接受int类型的“1”,但不能接受bool类型的1一样。MathDelegata的 参数类型定义 应该能够确定 MathDelegata可以代表的方法种类,再进一步讲,就是MathDelegata可以代表的方法 的 参数类型和返回类型,就是方法签名的意思。
于是,委托出现了:它定义了MathDelegata参数所能代表的方法的种类,也就是MathDelegata参数的类型。
NOTE:如果上面这句话比较绕口,我把它翻译成这样:string 定义了name参数所能代表的值的种类,也就是name参数的类型。
static int Count(int i, int j, MathDelegate myDelegata)
{
return myDelegata(i,j);
}
如你所见,委托MathDelegata出现的位置与 int相同,int是一个类型,那么MathDelegata应该也是一个类型,或者叫类(Class)。但是委托的声明方式和类却完全不同,这是怎么一回事?实际上,委托在编译的时候确实会编译成类。因为Delegate是一个类,所以在任何可以声明类的地方都可以声明委托。更多的内容将在下面讲述,现在,请看看这个范例的完整代码:
class Program
{
delegate int MathDelegate(int i, int j);//delegate 和 Delegate 的区别是什么
static int Add(int i,int j)
{
return i+j;
}
static int Subtract(int i,int j)
{
return i - j;
}
static int Multiply(int i,int j)
{
return i * j;
}
static int Devide(int i,int j)
{
return i / j;
}
static int Count(int i, int j, MathDelegate myDelegata)
{
return myDelegata(i,j);
}
static void Main(string[] args)
{
int result = Count(, , Add);
Console.WriteLine("加法结果是:{0}",result); result = Count(, ,Subtract);
Console.WriteLine("减法结果是:{0}", result); result = Count(, ,Multiply);
Console.WriteLine("乘法结果是:{0}", result); result = Count(, , Devide);
Console.WriteLine("除法结果是:{0}", result); Console.ReadKey();
}
我们现在对委托做一个总结:
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
说到这里我们已然可以把委托理解为一个类型或一个类,就想String一样,但是委托有一个特性不同于类型:可以将多个方法赋给同一个委托,或者叫将多个方法绑定到同一个委托,当调用这个委托的时候,将依次调用其所绑定的方法。我们称它为多播委托,在这个例子中,语法如下:
class Program
{
delegate int MathDelegate(int i, int j);//delegate 和 Delegate 的区别是什么
static int Add(int i,int j)
{
Console.WriteLine("加法");
return i+j;
}
static int Subtract(int i,int j)
{
Console.WriteLine("减法");
return i - j;
}
static int Multiply(int i,int j)
{
Console.WriteLine("乘法");
return i * j;
}
static int Devide(int i,int j)
{
Console.WriteLine("除法");
return i / j;
}
static int Count(int i, int j, MathDelegate myDelegata)
{
return myDelegata(i,j);
}
static void Main(string[] args)
{
//多播委托
MathDelegate myDelegate = new MathDelegate(Add);
myDelegate += Subtract;
myDelegate += Multiply;
myDelegate += Devide; int result = Count(, , myDelegate);
Console.WriteLine("结果是:{0}", result); Console.ReadKey();
}
}
运行结果为

由运行结果分析,当一个委托引用同时指向多个符合方法标识的方法时,此时即构成多播委托。其本质是对System.MulticastDelegate类(为System.Delegate的子类)的继承和实现。由于一个委托只能有一个返回值,故一般多播委托为void的(并非一定),若有返回值,则最终的返回结果及多播系列中最后一个方法的返回值。
当多播委托的引用只指向一个方法,则其使用方法与单播委托一样,但是若指向多个方法,则除第一个使用=,其他均用+=。注意这里,第一次用的“=”,是赋值的语法;第二次,用的是“+=”,是绑定的语法。如果第一次就使用“+=”,将出现“使用了未赋值的局部变量”的编译错误。例如:
MathDelegate myDelegate = new MathDelegate(Add);
myDelegate += Subtract;
myDelegate += Multiply;
myDelegate += Devide;
既然一个委托可以绑定方法,就有办法取消对方法的绑定,很容易想到这个语法:-=
//第三种方式:多播委托
MathDelegate myDelegate = new MathDelegate(Add);
myDelegate += Subtract;
myDelegate += Multiply;
myDelegate += Devide;
myDelegate -= Devide;//注意这里的写法
由上个例子改写运行结果:

我们看到除法没有了,是因为解除了对除法的绑定,最后一个方法是乘法,返回的结果是最后一个方法的运算结果。
C#深入浅出 C#语法中的重中之重——委托(四)的更多相关文章
- 简单说 JavaScript中的事件委托(下)
说明 上次我们说了一些,关于 JavaScript中事件委托的 基础知识,这次我们继续来看. 解释 先来一段代码 <!doctype html> <html lang="e ...
- 怎么理解js中的事件委托
怎么理解js中的事件委托 时间 2015-01-15 00:59:59 SegmentFault 原文 http://segmentfault.com/blog/sunchengli/119000 ...
- .Net Framework中的标准委托和事件_1
.Net Framework中的标准委托,已经定义在命名空间System中, namespace System { public delegate void EventHandler(object s ...
- 【Unity3D技巧】在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信 (二) : 引入中间层NotificationCenter
作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 一对多的观察者模式机制有什么缺点? 想要查看 ...
- C#语法中一个问号(?)和两个问号(??)的运算符是什么意思?
(1).C#语法中一个个问号(?)的运算符是指:可以为 null 的类型. MSDN上面的解释: 在处理数据库和其他包含不可赋值的元素的数据类型时,将 null 赋值给数值类型或布尔型以及日期类型的功 ...
- js实例分析JavaScript中的事件委托和事件绑定
我们在学习JavaScript中,难免都会去网上查一些资料.也许偶尔就会遇到“事件委托”(也有的称我“事件代理”,这里不评论谁是谁非.以下全部称为“事件委托”),尤其是在查JavaScript的事件处 ...
- C#语法中一个问号(?)和两个问号(??)的运算符
(1).C#语法中一个个问号(?)的运算符是指:可以为 null 的类型. MSDN上面的解释: 在处理数据库和其他包含不可赋值的元素的数据类型时,将 null 赋值给数值类型或布尔型以及日期类型的功 ...
- JQuery中的事件委托
JQuery 中的事件委托 定义 事件委托就是利用冒泡的原理,把事件加到父级上,通过判断事件来源的子集,执行相应的操作,事件委托首先可以极大减少事件绑定次数,提高性能:其次可以让新元素的子元素也可以拥 ...
- js中的事件委托或是事件代理
JavaScript(jQuery)中的事件委托 https://www.cnblogs.com/zhoushengxiu/p/5703095.html js中的事件委托或是事件代理详解 https: ...
随机推荐
- rsync服务器安装配置
#rsync指定端口号(10002)1 rsync -e 'ssh -p 10002' rsync (server -- client) #2014-3-3 -----------server---- ...
- 捉襟见肘之UIScrollView 【一】
参考地址:http://segmentfault.com/a/1190000002412930 另一个优秀的UIScrollView实践文章地址:http://tech.glowing.com/cn/ ...
- Nginx与服务器集群在它的配置文件中的配置
- 获取jsp页面的宽和高
var winWidth; var winHeight; function getResult() { if(window.innerWidth) { winWidth=window.innerWid ...
- swfUpload 上传图片
前端: <script src="~/Scripts/swfupload/swfupload.js"></script> <script src=&q ...
- tp中附件上传文件,表单提交
public function tianjia(){ $goods=D('Goods'); if(!empty($_POST)){ if($_FILES['f_goods_image']['error ...
- yum提示another app is currently holding the yum lock;waiting for it to exit
Another app 解决方法:rm -rf /var/run/yum.pid 来强行解除锁定,然后你的yum就可以运行了
- OBJ Loader Source Code
https://github.com/ChrisJansson/ObjLoader http://www.codeproject.com/Articles/798054/SimpleScene-d-s ...
- Shared Library Search Paths
在使用CodeLite编译动态库的时候,可以通过在Linker > Linker Options中添加: -install_name @executable_path/libXXX.so 的方式 ...
- NGUI架构和Draw Call合并原理
http://bbs.9ria.com/thread-282804-1-1.html http://www.unitymanual.com/blog-97-238.html