入行半年多了,委托干什么用的还不知道,真心说不过去了,关键对这东西有点恐惧,主要是被老师吓的,记得我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#语法中的重中之重——委托(四)的更多相关文章

  1. 简单说 JavaScript中的事件委托(下)

    说明 上次我们说了一些,关于 JavaScript中事件委托的 基础知识,这次我们继续来看. 解释 先来一段代码 <!doctype html> <html lang="e ...

  2. 怎么理解js中的事件委托

    怎么理解js中的事件委托 时间 2015-01-15 00:59:59  SegmentFault 原文  http://segmentfault.com/blog/sunchengli/119000 ...

  3. .Net Framework中的标准委托和事件_1

    .Net Framework中的标准委托,已经定义在命名空间System中, namespace System { public delegate void EventHandler(object s ...

  4. 【Unity3D技巧】在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信 (二) : 引入中间层NotificationCenter

    作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 一对多的观察者模式机制有什么缺点? 想要查看 ...

  5. C#语法中一个问号(?)和两个问号(??)的运算符是什么意思?

    (1).C#语法中一个个问号(?)的运算符是指:可以为 null 的类型. MSDN上面的解释: 在处理数据库和其他包含不可赋值的元素的数据类型时,将 null 赋值给数值类型或布尔型以及日期类型的功 ...

  6. js实例分析JavaScript中的事件委托和事件绑定

    我们在学习JavaScript中,难免都会去网上查一些资料.也许偶尔就会遇到“事件委托”(也有的称我“事件代理”,这里不评论谁是谁非.以下全部称为“事件委托”),尤其是在查JavaScript的事件处 ...

  7. C#语法中一个问号(?)和两个问号(??)的运算符

    (1).C#语法中一个个问号(?)的运算符是指:可以为 null 的类型. MSDN上面的解释: 在处理数据库和其他包含不可赋值的元素的数据类型时,将 null 赋值给数值类型或布尔型以及日期类型的功 ...

  8. JQuery中的事件委托

    JQuery 中的事件委托 定义 事件委托就是利用冒泡的原理,把事件加到父级上,通过判断事件来源的子集,执行相应的操作,事件委托首先可以极大减少事件绑定次数,提高性能:其次可以让新元素的子元素也可以拥 ...

  9. js中的事件委托或是事件代理

    JavaScript(jQuery)中的事件委托 https://www.cnblogs.com/zhoushengxiu/p/5703095.html js中的事件委托或是事件代理详解 https: ...

随机推荐

  1. RabbitMQctl命令

    RabbitMQControl RabbitMQ提供了可视化的网页供我们进行一些配置与操作,但是ctl的命令比UI来的专业的多,一些UI无法完成的操作就需要使用ctl命令来进行处理了 这里是官方的文档 ...

  2. PL/0编译器(java version) – SymbolTable.java

    1: package compiler; 2: //竟然没有对符号表检查大小,会溢出的. 3:   4: import java.io.IOException; 5:   6: public clas ...

  3. Linux下,使用Git管理 dotfiles(配置文件)

    1.管理你的 dotfiles 作为一个计算机深度使用者,并且长期使用 Linux 作为主要操作系统,折腾各种功能强大的软件是常有的事儿.这些软件有它们各自的配置文件,通常以 . 开头,因此有人管它们 ...

  4. elk系列3之通过json格式采集Nginx日志

    preface 公司采用的LNMP平台,跑着挺多nginx,所以可以利用elk好好分析nginx的日志.下面就聊聊它吧. 下面的所有操作都在linux-node2上操作 安装Nginx nginx是开 ...

  5. JavaWeb---总结(十六)JSP指令

    一.JSP指令简介 JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分. 在JSP 2.0规范中共定义了三个指令: pa ...

  6. gettextize与glib-gettextize的使用

    gettextize在各种场合都可以使用,用于支持多语言开发 glib-gettextize运行后,会修改po/Makefile.in.in文件,导致后续都必须运行glib-gettextize ge ...

  7. netty socket 客服端编程

    package com.ming.netty.nio; 2 3 import io.netty.bootstrap.Bootstrap; 4 import io.netty.channel.Chann ...

  8. JQuery------如何判断当前点击的是否是哪个类

    $(document).ready(function () { $("html").click(function (e) { if (e.target == $(".ad ...

  9. Spring解析实践

    这几天重新把传智播客的黎活明的Spring2.5的教程学习了一遍,跟着上面的解析Spring的过程跟着制作了一个简单的Spring IOC和Spring AOP,先在贴上来给大家参考一下. 1:管理B ...

  10. HTML学习体会

    HTML介绍 华丽的网页界面,都是由静态网页和一些动态效果,插入的视频,和flash等等,不得不说,静态网页的制作,是学习网页的必经之路,可见静态网页在学习网页的前端是十分重要.静态网页主要是通过ht ...