委托提供了类似C++中函数指针的功能,简单地说委托类型就是面向对象函数指针,
不过C++的函数指针只能够指向静态的方法,
而委托除了可以指向一个静态的方法之外还可以指向对象实例的方法,并且委托是完全面向对象且使用安全的类型。
也就是说:委托可以看成是一种类型安全的函数指针,它用来代理一类符合其要求的方法(包括静态方法和动态方法即实例的方法),同时它又可以作为一个方法的参数进行传。
对“符合其要求”的解释:委托的 返回类型 和 参数 要与被代理的方法的 返回类型 和 参数 一致(不仅类型一致,参数个数也要相同)。
委托的优点:委托允许程序设计师可以在执行时期传入方法的名称动态地决定欲调用的方法,灵活性和扩张性非常强。
委托一般用在事件、多线程和通用类库中。
下面列举了5个示例对委托的概念和基本用法进行说明(这些例子来自陈广老师和楚广明老师的课堂,自己稍作了修改和融合)
为了省去创建GUI那些繁琐的步骤,更清晰地逼近委托的本质,接下来的所有程序都是控制台程序,程序最后的Console.ReadKey()是为了使程序中途停下来,以便看清楚执行过程中的输出。
using System; //一、代理静态方法示例 namespace DelegateDemo { //委托的本质就是一个类,任何可以声明类的地方都可以声明委托 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(string[] args) { EatDelegate zsEat = new EatDelegate(ZsEat);//委托的实例化;代理的静态方法 zsEat("西瓜");//委托的使用; EatDelegate lsEat = LsEat;//代理的静态方法,直接将方法名传递给委托变量 lsEat("香蕉"); EatDelegate wwEat = new EatDelegate(WwEat);//委托的实例化;代理的静态方法 EatDelegate eatChain; Console.WriteLine("张三、李四、王五开座谈会"); eatChain = zsEat + lsEat + wwEat;//委托链 eatChain("西瓜"); Console.WriteLine(); Console.WriteLine("李四出去接电话"); eatChain -= lsEat; eatChain("香蕉"); Console.WriteLine(); Console.WriteLine("李四回来了"); eatChain += lsEat; eatChain("橘子"); Console.WriteLine(); Console.WriteLine("这是赵六来了"); eatChain += delegate(string food) { Console.WriteLine("赵六吃:" + food); };//匿名方法; eatChain("苹果"); Console.ReadKey(); } } }
输出结果:
二、
using System; //二、代理动态方法示例 namespace DelegateDemo { //委托的本质就是一个类,任何可以声明类的地方都可以声明委托 delegate void EatDelegate(string food);//委托的声明;其返回类型和参数要与被代理的方法的返回类型和参数一致 class Man { private string name; public Man(string name) { this.name = name; } public void Eat(string food)//被代理的方法 { Console.WriteLine(name + "吃:" + food); } } class MyDelegate { static void Main(string[] args) { Man zs = new Man("张三"); Man ls = new Man("李四"); Man ww = new Man("王五"); EatDelegate zsEat = new EatDelegate(zs.Eat);//委托的实例化;代理的动态方法,即实例的方法 zsEat("西瓜");//委托的使用; EatDelegate lsEat = ls.Eat;//代理的动态方法,直接将实例的方法名传递给委托变量 lsEat("香蕉"); EatDelegate wwEat = new EatDelegate(ww.Eat);//委托的实例化;代理的动态方法 EatDelegate eatChain; Console.WriteLine("张三、李四、王五开座谈会"); eatChain = zsEat + lsEat + wwEat;//委托链 eatChain("西瓜"); Console.WriteLine(); Console.WriteLine("李四出去接电话"); eatChain -= lsEat; eatChain("香蕉"); Console.WriteLine(); Console.WriteLine("李四回来了"); eatChain += lsEat; eatChain("橘子"); Console.WriteLine(); Console.WriteLine("这是赵六来了"); eatChain += delegate(string food) { Console.WriteLine("赵六吃:" + food); };//匿名方法; eatChain("苹果"); Console.ReadKey(); } } }
输出结果:与一相同。
三、
using System; //三、代理作为方法的参数示例 namespace DelegateDemo { delegate void EatDelegate(string food); class Man { private string name; public Man(string name) { this.name = name; } public void Eat(string food) { Console.WriteLine(name + "吃:" + food); } } class MyDelegate { static void EatTogether(string food, params EatDelegate[] values)//代理作为方法的参数进行传递 { if (values == null) { Console.WriteLine("座谈会结束"); } else { EatDelegate eatChain = null; foreach (EatDelegate value in values) { eatChain += value; } eatChain(food); } } static void Main(string[] args) { Man zs = new Man("张三"); Man ls = new Man("李四"); Man ww = new Man("王五"); EatDelegate zsEat = new EatDelegate(zs.Eat); EatDelegate lsEat = new EatDelegate(ls.Eat); EatDelegate wwEat = new EatDelegate(ww.Eat); Console.WriteLine("张三、李四、王五开座谈会"); EatTogether("西瓜", zsEat, lsEat, wwEat); Console.WriteLine(); Console.WriteLine("李四出去接电话"); EatTogether("香蕉", zsEat, wwEat); Console.WriteLine(); Console.WriteLine("李四回来了"); EatTogether("橘子", zsEat, lsEat, wwEat); Console.WriteLine(); EatTogether(null, null); Console.ReadKey(); } } }
输出结果:
四、
using System; //四、执行时传入方法的名称动态地决定欲调用的方法 namespace DelegateDemo { class MyDelegate { public delegate int GenericFun(int a, int b); public static int Add(int a, int b) { return a + b; } public static int Sub(int a, int b) { return a - b; } public static int PrintResult(GenericFun action, int a, int b)//执行时传入方法的名称动态地决定欲调用的方法 { int result = action(a, b); return result; } static void Main(string[] args) { Console.WriteLine("3+4=" + PrintResult(Add, 3, 4)); Console.WriteLine("3-4=" + PrintResult(Sub, 3, 4)); Console.ReadKey(); } } }
输出结果:
3+4=7
3-4=-1
五、
using System; //五、最后一个例子 namespace DelegateDemo { delegate int MathOperationsDelegate(int value); class MathOperations { public static int MultiByTwo(int value) { return value * 2; } public static int Square(int value) { return value * value; } } class MyDelegate { public static void ProcessAndDisplayRusult(MathOperationsDelegate action, int value) { int result = action(value); Console.WriteLine(result); } static void Main() { MathOperationsDelegate[] operations = { new MathOperationsDelegate(MathOperations.MultiByTwo), new MathOperationsDelegate(MathOperations.Square) }; for (int i = 0; i < operations.Length; i++) { Console.WriteLine("使用operation[{0}]", i); ProcessAndDisplayRusult(operations[i], 3); } Console.ReadKey(); } } }
输出结果:
使用operation[0]
6
使用operation[1]
9