第七讲 委托1
委托是一种安全地封装方法的类型,它与 C 和 C++ 中的函数指针类似。与 C 中的函数指针不同,
委托是面向对象的、类型安全的和保险的。委托的类型由委托的名称定义。
下面的示例声明了一个名为 Del 的委托,该委托可以封装一个采用字符串作为参数并返回 void 的方法。
public delegate void Del(string message);委托具有以下特点:
-
委托类似于 C++ 函数指针,但它是类型安全的。
-
委托允许将方法作为参数进行传递。
-
委托可用于定义回调方法。
-
委托可以链接在一起;例如,可以对一个事件调用多个方法。
-
方法不需要与委托签名精确匹配。有关更多信息,请参见协变和逆变。
-
C# 2.0 版引入了匿名方法的概念,此类方法允许将代码块作为参数传递,以代替
单独定义的方法。
- using System;
- //创建一个类
- class MyDelegate
- {
- //创建一个静态函数:张三吃东西。
- //字符串的参数food
- static void zsEat(string food)
- {
- //在屏幕上打印
- Console.WriteLine("张三吃" + food);
- }
- static void Main()
- {
- //调用
- zsEat("西瓜");
- }
- }
这个程序很简单,就是为了打印张三吃食物。大家自己编译执行下,不是很难理解。
结果是张三吃西瓜。下面我们来改下这段程序,通过委托的方法来调用张三吃东西
这个函数。
- using System;
- /// <summary>
- /// 声明一个EatDelegate这样的委托
- /// 委托的声明首先使用了delegate关键字,然后是委托的返回值void,括号里是委托的参数
- /// 委托原型必须跟域委托的方法具有相同的返回值和参数(个数也必须一致)
- /// 域委托的方法就是MeDelegate类下的void zsEat(string food)方法
- /// 委托的本质就是一个类,任何可以声明的地方都可以声明委托
- /// </summary>
- /// <param name="food"></param>
- delegate void EatDelegate(string food);
- class MyDelegate
- {
- static void zsEat(string food)
- {
- Console.WriteLine("张三吃" + food);
- }
- static void Main()
- {
- //下面我们就可以通过调用委托来调用张三吃西瓜这个函数了
- //这里声明了一个委托的实例zs并给它初始化
- //EatDelegate里面带的参数是我们域代理的函数的名称
- //这就意味着zs这个委托实例它所代理的函数的名字叫zsEat,两者之间能联系
- EatDelegate zs = new EatDelegate(zsEat);
- //进行调用使用函数
- zs("西瓜");
- }
- }
我们进行执行编译代码,结果和上面是一样的。而这一次我们并没有直接
使用zsEat这个函数,而是通过代理zs来调用它,它们的执行效果都是一样
的。好,接下来张三一个人吃西瓜觉得不过瘾,我们添加李四等人,
代码如下:
- using System;
- delegate void EatDelegate(string food);
- class MyDelegate
- {
- static void zsEat(string food)
- {
- Console.WriteLine("张三吃" + food);
- }
- //添加一个李四吃东西函数
- static void lsEat(string food)
- {
- Console.WriteLine("李四吃" + food);
- }
- //添加一个王五吃东西函数
- static void wwEat(string food)
- {
- Console.WriteLine("王五吃" + food);
- }
- static void Main()
- {
- EatDelegate zs = new EatDelegate(zsEat);
- EatDelegate ls = new EatDelegate(lsEat);
- EatDelegate ww = new EatDelegate(wwEat);
- //进行调用使用函数
- zs("西瓜");
- ls("西瓜");
- ww("西瓜");
- }
- }
屏幕上也打印出来了张三,王五,李四都在吃西瓜,没有什么问题。
但是他们都在吃同一样东西西瓜,为什么我们要输入三次呢?这样
不是很麻烦嘛,有没有什么办法可以只输入一次西瓜,而同时都调用
了这3个函数了呢?有的,委托链可以实现这样的功能。这也是委托一
个十分强大的地方,我们修改下代码,声明委托链:
- using System;
- delegate void EatDelegate(string food);
- class MyDelegate
- {
- static void zsEat(string food)
- {
- Console.WriteLine("张三吃" + food);
- }
- static void lsEat(string food)
- {
- Console.WriteLine("李四吃" + food);
- }
- static void wwEat(string food)
- {
- Console.WriteLine("王五吃" + food);
- }
- static void Main()
- {
- EatDelegate zs = new EatDelegate(zsEat);
- EatDelegate ls = new EatDelegate(lsEat);
- EatDelegate ww = new EatDelegate(wwEat);
- //声明一个委托链,不需要实例化
- EatDelegate eatChain;
- //接下来把张三李四王五都加进这个委托链
- eatChain = zs + ls + ww;
- //现在让他们一起吃西瓜
- eatChain("西瓜");
- }
- }
我们保存代码执行,效果如下:
我们看,我们只使用了一次西瓜的参数,就让张三李四王五同
时吃西瓜了。我们回过头来再来看下代码,(eatChain = zs + ls + ww)
在委托链eatChain中,只要把张三李四王五这几个委托的实例加到
这个委托链里面,之后向调用方法一样调用这个委托链eatChain("西瓜"),它就会依次
按照上面加入的顺序去执行这几个委托所对应的函数了。
好,接下来我们把程序变得更具有逻辑性些:
- using System;
- delegate void EatDelegate(string food);
- class MyDelegate
- {
- static void zsEat(string food)
- {
- Console.WriteLine("张三吃" + food);
- }
- static void lsEat(string food)
- {
- Console.WriteLine("李四吃" + food);
- }
- static void wwEat(string food)
- {
- Console.WriteLine("王五吃" + food);
- }
- static void Main()
- {
- EatDelegate zs = new EatDelegate(zsEat);
- EatDelegate ls = new EatDelegate(lsEat);
- EatDelegate ww = new EatDelegate(wwEat);
- //声明一个委托链,不需要实例化
- EatDelegate eatChain;
- //张三李四王五刚刚放假,非常高兴决定搞一个party
- Console.WriteLine("张三,李四,王五开座谈会");
- //他们三个人都在吃西瓜呀
- eatChain = zs + ls + ww;
- eatChain("西瓜");
- //这个时候,李四的电话响了
- Console.WriteLine("李四出去接电话");
- //李四就吃不了西瓜了
- eatChain -= ls;
- //张三和王五继续吃香蕉
- eatChain("香蕉");
- //过了一会李四回来了
- Console.WriteLine("李四回来了");
- eatChain += ls;
- //他们接着吃桔子
- eatChain("桔子");
- }
- }
我们来看下效果:
我们来看一下,前面他们3个人吃西瓜我们都理解了,这个时候李四
出去接电话了.我们用一个"-="将ls这个实例开除出eatChain这个
委托链,接着执行吃香蕉.我们可以在屏幕上看出只有张三和王五在
吃香蕉。这时李四又回来了,李四也要继续吃东西eatChain += ls
把李四又加了进去,接着他们一起吃桔子eatChain("桔子"),我们看
结果他们3个人又都在一起吃桔子了。
C#其实重载了-=和+=这2个操作符来对委托链里的元素进行加减操作,
从而使得我们可以随意控制委托链里的元素个数。
- static void zsEat(string food)
- {
- Console.WriteLine("张三吃" + food);
- }
- static void lsEat(string food)
- {
- Console.WriteLine("李四吃" + food);
- }
- static void wwEat(string food)
- {
- Console.WriteLine("王五吃" + food);
- }
向这样只有几句话的委托方法微软提供了一种非常简单的书
写方式给我们,使得我们可以更方便的写出委托,
下面我们来修改下代码:
- using System;
- delegate void EatDelegate(string food);
- class MyDelegate
- {
- static void Main()
- {
- //声明一个委托链,给他赋一个空值
- EatDelegate eatChain = null;
- //三个人都在吃西瓜
- eatChain += delegate(string food) { Console.WriteLine("张三吃" + food); };
- eatChain += delegate(string food) { Console.WriteLine("李四吃" + food); };
- eatChain += delegate(string food) { Console.WriteLine("王五吃" + food); };
- eatChain("西瓜");
- }
- }
我们编译执行可以得到张三李四王五都在吃西瓜。虽然我们没有书写
zsEat(string food),lsEat(string food),wwEat(string food)
这些方法,但是呢我们把这些方法直接加到了委托链里面。当委托链执行
的时候,得出了刚才一样的效果(屏幕上3个人吃西瓜)。这个就是C#2.0新
增的匿名方法,它使的我们更加容易的去创建委托,有关匿名方法的讲解
可以去MSDN上的webcast网络讲座上,李建忠老师的《C#2.0锐利体验系
列课程》中的《匿名方法,迭代器》有深入详细的讲解,
若果感兴趣可以去下载学习。