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: ...
随机推荐
- dedecms /member/resetpassword.php SQL Injection Vul
catalog . 漏洞描述 . 漏洞触发条件 . 漏洞影响范围 . 漏洞代码分析 . 防御方法 . 攻防思考 1. 漏洞描述 DEDEcms SQL注入漏洞导致可以修改任意用户密码 2. 漏洞触发条 ...
- 修改oracle系统用户system的密码
C:\Users\Administrator>echo %ORACLE_SID% %ORACLE_SID% C:\Users\Administrator>set ORACLE_SID=or ...
- 无法启动此程序,因为计算机中丢失MSVCP110.dll
安装Visual C++ Redistributable for Visual Studio 2012 有arm.x86.x64有三个版本. 如果应用程序为debug版本而不是release版本,可能 ...
- 基于UDP协议的程序设计
使用UdpClient类进行编程 UdpClient类的使用方法 第一阶段 创建UdpClient实例 UdpClient udpClient = new UdpClient(); IPAddress ...
- python列表、元组、字典(四)
列表 如:[11,22,33,44,44].['TangXiaoyue', 'bruce tang'] 每个列表都具备如下功能: class list(object): ""&qu ...
- css编写规范
一.注释规范 1.文件顶部注释(推荐使用) /* * @description: 中文说明 * @author: name * @update: name (2013-04-13 18:32) */ ...
- POJ3292 Semi-prime H-numbers
传送门: 刷<数论一本通>时看到的题,简单记录一下. 题目大意(照抄书上的):形如4n+1的数被称为H数,乘法在H数组成的集合内是封闭的.在这个集合中是能被1和本身整除的数叫H-素数,其余 ...
- WSAStartup
WSAStartup,是Windows Sockets Asynchronous的启动命令.Windows下的网络编程接口软件 Winsock1 或 Winsock2 里面的一个命令. 外文名 WSA ...
- pyinstaller 官方介绍
http://www.pyinstaller.org/ pyinstaller支持多个平台,windows,linux,mac,兼容多个第三方包,包括pyqt,django,matplotlib Py ...
- eclipse安装springsource-tool-suite
到http://spring.io/tools/sts/all找到安装的eclipse对应的springsource-tool-suite版本,复制下载的网址 然后在eclipse的install n ...