[.net 面向对象编程基础 ] ( 20) 委托
上节在讲到 LINQ 的匿名方法中说到了委托,不过比较简单,没了解清楚没关系,这节中会详细说明委托。
1.什么是委托 ?
学习委托,我想说,学会了就感觉简单的不能再简单了,没学过或都不愿了解的人,看着就头大,其实很简单。委托在 .net 面向对象编程和学习设计模式中非常重要,是学习 .net 面向对象编程必须要学会并掌握的。
委托从字面上理解,就是把做一些事情交给别人来帮忙完成。在 C# 中也可以这样理解,委托就是动态调用方法。这样说明,就很好理解了。
平时我们会遇到这样的例子需要处理,比如有一个动物园( Zoo )(我还是以前面的动物来说吧)里面有狗( Dog )、鸡 (Chicken) 、羊 (Sheep) ……,也许还会再进来一些新品种。参观动物员的人想听动物叫声,那么可以让管理员协助(动物只听懂管理员的),这样就是一个委托的例子。
在实现委托之前,我们先看一下委托的定义:
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用 If-Else(Switch) 语句,同时使得程序具有更好的可扩展性。
委托 (delegate) ,有些书上叫代理或代表,都是一个意思,为了避免了另一个概念代理( Proxy )混淆,还是叫委托更好一些。
学过 c++ 的人很熟悉指针, C# 中没有了指针, 使用了委托,不同的是,委托是一个安全的类型,也是面向对象的。
2. 委托的使用
委托 (delegate) 的声明的语法如下:
定义委托基本上是定义一个新类,所以可以在定义类的任何地方定义委托,既可以在另一个类的内部定义,也可以在任何类的外部定义,还可以在命名空间中把委托定义为顶层对象。根据定义的可见性,可以在委托定义上添加一般的访问修饰符: public 、 private、protected等:
实际上,“定义一个委托”是指“定义一个新类”。只是把 class 换成了 delegate 而已,委托实现为派生自基类 System. Multicast Delegate的类,System.MulticastDelegate又派生自基类System.Delegate。
下面我们使用委托来实现上面动物园的实例,实现如下:
1 /// <summary> 2 /// 动物类 3 /// </summary> 4 class Zoo 5 { 6 public class Manage 7 { 8 public delegate void Shout(); 9 public static void CallAnimalShout(Shout shout) 10 { 11 shout(); 12 } 13 } 14 public class Dog 15 { 16 string name; 17 public Dog(string name) 18 { 19 this.name = name; 20 } 21 public void DogShout() { 22 23 Console.WriteLine("我是小狗:" + this.name + "汪~汪~汪"); 24 } 25 } 26 public class Sheep 27 { 28 string name; 29 public Sheep(string name) 30 { 31 this.name = name; 32 } 33 public void SheepShout() 34 { 35 Console.WriteLine("我是小羊:" + this.name + "咩~咩~咩"); 36 } 37 } 38 public class Checken 39 { 40 string name; 41 public Checken(string name) 42 { 43 this.name = name; 44 } 45 public void ChickenShout() 46 { 47 Console.WriteLine("我是小鸡:" + this.name + "喔~喔~喔"); 48 } 49 } 50 }
动物园除了各种动物外,还有动物管理员,动物管理员有一个委托。调用如下:
//参观者委托管理员,让某种动物叫 Zoo.Dog dog=new Zoo.Dog("汪财"); Zoo.Manage.Shout shout = new Zoo.Manage.Shout(dog.DogShout); //管理员收到委托传达给动物,动物执行主人命令 Zoo.Manage.CallAnimalShout(shout);
运行结果如下:
上面的实例实现了委托的定义和调用 , 即间接的调用了动物叫的方法。肯定有人会说,为什么不直接调用小狗叫的方法,而要绕一大圈来使用委托。如果只是简单的让一种动物叫一下,那么用委托确实是绕了一大圈,但是如果我让让狗叫完,再让羊叫,再让鸡叫,反反复复要了好几种动物的叫声,最后到如果要结算费用,谁能知道我消费了多少呢?如果一次让几种动物同时叫呢,我们是不是要再写一个多个动物叫的方法来调用呢?当遇到复杂的调用时委托的作用就体现出来了,下面我们先看一下,如何让多个动物同时叫,就是下面要说的多播委托。
委托需要满足 4 个条件:
a. 声明一个委托类型
b. 找到一个跟委托类型具有相同签名的方法(可以是实例方法,也可以是静态方法)
c. 通过相同签名的方法来创建一个委托实例
c.
通过委托实例的调用完成对方法的调用
每个委托都只包含一个方法调用,调用委托的次数与调用方法的次数相同。如果调用多个方法,就需要多次显示调用这个委托。当然委托也可以包含多个方法,这种委托称为多播委托。
当调用多播委托时,它连续调用每个方法。在调用过程中,委托必须为同类型,返回类型一般为 void ,这样才能将委托的单个实例合并为一个多播委托。如果委托具有返回值和 / 或输出参数,它将返回最后调用的方法的返回值和参数。
下面我们看一下,调用“狗,鸡,羊”同时叫的实现:
//声明委托类型 Zoo.Manage.Shout shout; //加入狗叫委托 shout = new Zoo.Manage.Shout(new Zoo.Dog("小哈").DogShout); //加入鸡叫委托 shout += new Zoo.Manage.Shout(new Zoo.Checken("大鹏").ChickenShout); //加入羊叫委托 shout += new Zoo.Manage.Shout(new Zoo.Sheep("三鹿").SheepShout); //执行委托 Zoo.Manage.CallAnimalShout(shout); Console.ReadLine();
运行结果如下:
上面的示例,如果我们感觉还不足以体现委托的作用。我们假动物除了会叫之外,还有其它特技。狗会表演“捡东西( PickUp )” , 羊会踢球 (PlayBall), 鸡会跳舞 (Dance)
观众想看一个集体表演了,让狗叫 1 次,抢一个东西回来 ; 羊叫 1 次踢 1 次球,鸡叫 1 次跳 1 只舞。 然后,顺序倒过来再表演一次。如果使用直接调用方法,那么写代码要疯了,顺序执行一次,就顺序写一排方法代码,要反过来表演,又要倒过来写一排方法。这还不算高难度的表演,假如要穿插进行呢?使用委托的面向对象特征,我们实现这些需求很简单。看代码:
首先我们改进一下羊,狗,鸡,让他们有一个特技的方法。
1 /// <summary> 2 /// 动物类 3 /// </summary> 4 class Zoo 5 { 6 public class Manage 7 { 8 public delegate void del(); 9 10 /// <summary> 11 /// 动物表演 12 /// </summary> 13 /// <param name="obj"></param> 14 /// <param name="shout"></param> 15 public static void CallAnimal(del d) 16 { 17 d(); 18 } 19 } 20 public class Dog 21 { 22 string name; 23 public Dog(string name) 24 { 25 this.name = name; 26 } 27 public void DogShout() 28 { 29 Console.WriteLine("我是小狗:"+this.name+"汪~汪~汪"); 30 } 31 public void PickUp() 32 { 33 Console.WriteLine("小狗" + this.name + " 捡东西 回来了"); 34 } 35 } 36 public class Sheep 37 { 38 string name; 39 public Sheep(string name) 40 { 41 this.name = name; 42 } 43 public void SheepShout() 44 { 45 Console.WriteLine( "我是小羊:"+this.name+" 咩~咩~咩 "); 46 } 47 public void PlayBall() 48 { 49 Console.WriteLine("小羊" + this.name + " 打球 结束了"); 50 } 51 } 52 53 public class Chicken 54 { 55 string name; 56 public Chicken(string name) 57 { 58 this.name = name; 59 } 60 public void ChickenShout() 61 { 62 Console.WriteLine("我是小鸡:"+this.name+"喔~喔~喔"); 63 } 64 public void Dance() 65 { 66 Console.WriteLine("小鸡" + this.name + " 跳舞 完毕"); 67 } 68 } 69 }
调用如下:
1 //多播委托(二)动物狂欢 2 3 //挑选三个表演的动物 4 Zoo.Dog dog = new Zoo.Dog("小哈"); 5 Zoo.Chicken chicken = new Zoo.Chicken("大鹏"); 6 Zoo.Sheep sheep = new Zoo.Sheep("三鹿"); 7 8 //加入狗叫委托 9 Zoo.Manage.del dogShout = dog.DogShout; 10 //加入鸡叫委托 11 Zoo.Manage.del chickenShout = chicken.ChickenShout; 12 //加入羊叫委托 13 Zoo.Manage.del sheepnShout = sheep.SheepShout; 14 15 //加入狗表演 16 Zoo.Manage.del dogShow = new Zoo.Manage.del(dog.PickUp); 17 ; //加入鸡表演 18 Zoo.Manage.del chickenShow = new Zoo.Manage.del(chicken.Dance); 19 //加入羊表演 20 Zoo.Manage.del sheepShow = new Zoo.Manage.del(sheep.PlayBall); 21 22 23 //构造表演模式 24 //第一种表演方式:狗叫1次抢一个东西回来;羊叫1次踢1次球;鸡叫1次跳1只舞; 25 Zoo.Manage.del del = dogShout + dogShow + chickenShout + chickenShow + sheepnShout + sheepShow; 26 //执行委托 27 Zoo.Manage.CallAnimal(del); 28 29 30 Console.WriteLine("/n第二种表演,顺序反转/n"); 31 //第二种表演,顺序反转 32 var del2 = del.GetInvocationList().Reverse(); 33 //执行委托 34 foreach (Zoo.Manage.del d in del2) 35 Zoo.Manage.CallAnimal(d); 36 Console.ReadLine();
运行结果如下:
<明天继续。。。。未完>
==============================================================================================
返回目录
<如果对你有帮助,记得点一下推荐哦,有不明白的地方或写的不对的地方,请多交流>==============================================================================================