1、引子ide
在正式说委托前,我先给一个例子,而后引出后面要说的委托。spa
很简单,就是一个机器人打招呼的。code
代码清单1.1:对象
class Robot { public void GreetByChinese(string name) { Console.WriteLine("你好," + name + "!"); } public void GreetByEnglish(string name) { Console.WriteLine("Hello," + name + "!"); } //打招呼 public void DoGreet(string name,string lang) { switch (lang) { case "chinese": GreetByChinese(name); break; case "english": GreetByEnglish(name); break; default: break; } } } class Program { static void Main(string[] args) { //实例化机器人对象 Robot robot = new Robot(); string name = Console.ReadLine(); robot.DoGreet(name,"chinese"); robot.DoGreet(name,"english"); Console.Read(); } }
代码清单1.1中建立了一个机器人类,类中封装了两个打招呼的方法和一个调用这两个方法的公共方法。DoGreet方法中,只要带name和switch中的条件,就能够打印出对应语言打招呼的语句。blog
那么,若是我要增长其余的语言,如法语、日语、韩语等,我除了增长对应的方法,还须要改DoGreet方法里的case语句,维护量较大。那有什么办法能够解决这种尴尬呢?string
一种比较简单的方法是,直接将方法做为参数(变量),传给另外一个方法(DoGreet),在其中执行便可。it
但咱们都知道,能做为方法的参数的是某一类型的对象或变量,而方法是个什么类型呢?确实找不出方法对应的类型。但依然有种方法能够间接的将方法做为一个参数来使用,这便引出了,下面要提到的“委托”。 event
2、关于委托,微软给出的定义以下:class
“委托用于将方法做为参数传递给其余方法。”变量
早在C#1.0时,就已开始支持这个特性(用过VS2003的园友,应该是最清楚不过了)。关于微软给出的定义,已经很好理解了:咱们利用委托,把方法做为一个参数(变量)传递给其余的方法,从而由其余方法来代为执行这个当作参数的方法里的动做。
3、那么怎么去使用委托呢?
使用委托,基本要按照以下步骤实现:
一、定义一个委托类型
访问修饰符 delegate 返回类型 委托类型名称(参数列表);
Ex:public delegate void Greet(string name);
二、建立一个执行某动做的方法(返回类型和参数列表须与委托类型相同)
访问修饰符 返回类型 方法名称(参数列表){......}
Ex:public void GreetByChinese(string name)
{
Console.WriteLine(“你好,”+name+“!”);
}
三、实例化委托类型
委托类型名称 委托对象名称=方法名称;
Ex:Greet greet=GreetByChinese;
四、开始使用,执行操做
委托对象名称(参数列表);
或:委托对象名称.Invoke(参数列表);
Ex:greet(“季节旋风”); 或:greet.Invoke(“季节旋风”);
如上,就这么个简单的流程,是否是很简单。但这里,可能有人会说,定义中不是将方法做为参数传给另外一个方法吗?怎么没有这么用?其实这个不用担忧,咱们已经在步骤3中将方法引用给了greet对象,既然是对象,那么久能够做为方法的参数,就能够很好地解决这个疑问。
具体的看下面的代码清单3.1:
//一个经常使用的委托,打招呼 delegate void Greet(string name); //一个机器人类,封装打招呼 class Robot { public void GreetByChiness(string name) { Console.WriteLine("你好," + name + "!"); } public void GreetByEnglish(string name) { Console.WriteLine("Hello," + name + "!"); } public void GreetByJapaness(string name) { Console.WriteLine("こんにちは," + name + "!"); } //打招呼 public void DoGreet(string name, Greet greet) { greet(name); } } class SampleDelegate { static void Main(string[] args) { //实例化机器人对象 Robot robot = new Robot(); string name = Console.ReadLine(); //经过把方法做为变量来实现打招呼 robot.DoGreet(name, robot.GreetByChiness); robot.DoGreet(name, robot.GreetByEnglish); robot.DoGreet(name, robot.GreetByJapaness); Console.Read(); } }
执行结果以下:
依然是机器人大招呼的例子,但用到了委托,这样一来是否是更简洁了?这里已经能够轻松地将方法做为参数传递给执行方法(DoGreet)中,并在其中执行操做。
4、合并委托(多路广播委托)
委托对象的一个有用属性是:可使用 “+” 运算符将多个对象分配给一个委托实例。 多播委托包含已分配委托的列表。 在调用多播委托时,它会按顺序调用列表中的委托。 只能合并相同类型的委托。 “-” 运算符可用于从多播委托中移除组件委托。
依然用机器人打招呼的例子来说,这里就再也不使用DoGreet方法了,直接在Main方法中来作“打招呼”动做。以下(代码清单4.1):
Greet greet = robot.GreetByChiness; greet += robot.GreetByEnglish; greet += robot.GreetByJapaness; greet(name);
在运行时,它会按顺序执行调用的方法,以下图:
值得注意的是,只有对委托对象greet初始化后才可进行多播操做,例以下面的这种写法就是错误的:
Greet greet+= robot.GreetByChiness;
在执行移除(“-”)操做时,跟合并操做相似,但它是从委托中移除已有的方法。例如将代码清单4.1的代码后面加上,下面代码(代码清单4.2):
Console.WriteLine("移除日语后:"); greet -= robot.GreetByJapaness; greet(name);
那么第二次greet时,会少一个日语问候,执行结果以下图: