写在前
委托对于我这种比较专注于前端开发的人来说,真的是不好理解。最近看了一个东西,里面用了这个,有点傻眼了,我努力去弄懂这个东西,但是真不知道怎么去懂。很显然这个东西很有用,很多东西都是基于委托来实现的,本着究底的学习态度到处去找比较通俗易懂的资料,好难找啊。开始只找到了msdn上关于这个的介绍---delegate。
如大牛所说,这篇博文要讲述什么是委托?为什么要使用它及事件的由来?委托和事件对Observer设计模式的意义等等。
网上说委托就是可以实现把方法做为变量来传递的东西。
这个东西真不好理解,所以就不用管它是什么意思了,直接来看代码。
public void GreetPeople(string name)
{
//do something
EnglishGreeting(name);
}
public void EnglishGreeting(string name)
{
Console.WriteLine("hello, "+name);
}
GreetPeople用于向某人打招呼,向其传递参数name的时候,比如:welpher,在这个方法中,将会调用别一个方法EnglishGreeting,向其传递name参数,在屏幕输出一句英文的打招呼句子“hello, welpher"。
如果以后要对这个方法进行扩展,比如全球化,要加入各种语言的打招呼的方法,比如加入中文的打招呼句子。
public void ChineseGreeting(string name)
{
Console.WriteLine("你好, "+name);
}
加了一个方法后上面的GreetPeople也要改一下了,不然不知道什么时候该调用哪个方法了。
public enum Language
{
English,Chinese
}
public void GreetPeople(string name,Language lang)
{
//do somethig
switch(lang)
{
case Language.English:
EnglishGreeting(name);break;
case Language.Chinese:
ChineseGreeting(name);break;
}
}
好了,满足了客户的要求。但是不得不说这个解决方案可扩展性是很差的,以后再添加其它语言版的打招呼时,不得不反复的修改代码。
先来看看GreetPeople的方法签名:
public void GreetPeople(string name, Language lang)
这个方法里,string 是参数类型,name是参数变量,我们传递什么样的名字进去就显示什么名字,不管这个名字是哪国语言。
回到之前,向这个函数传递一个方法那该多好,传递EnglishGreeting就代表EnglishGreeting()这个方法,传递ChineseGreeting就代表ChineseGreeting()这个方法。给这个方法添加一个参数DoGreeting,那是不是可以像给name赋值一样,在调用GreetPeople()的时候,给这个DoGreeting赋值么?
public void GreetPeople(string name, *** DoGreeting)
{
DoGreeting(name);
}
这个位置通常放置的应该是参数的类型,应该有个可以代表方法的参数,并改写GreetPeople方法,但是这个应该是什么类型才能代表DoGreeting呢?
回头看看EnglishGreeting和ChineseGreeting,这两个方法都接受一个string类型的参数,只能接受string类型,其它类型是不行的。所以DoGreeting方法的参数类型是确定的。
本例用委托的方法来实现的话,完整例子如下:
using System;
using System.Collections.Generic;
using System.Text;
namespace Delegate
{
//定义委托,它定义了可以代表的方法的类型
public delegate void GreetingDelegate(string name);
class Program
{
private static void EnglishGreeting(string name)
{
Console.WriteLine("hello, "+name);
}
private static void ChineseGreeting(string name)
{
Console.WriteLine("你好, "+name);
}
//此方法接受一个GreetingDelegate类型的方法做为参数
private static void GreetPeople(string name,GreetingDelegate DoGreeting)
{
DoGreeting(name);
}
static void Main(string[] args)
{
GreetPeople("welpher",EnglishGreeting);
GreetPeople("锋",ChineseGreeting);
Console.ReadKey();
}
}
}
函数绑定到委托
通过上面的例子,那个要传的东西就叫做委托。上面的例子中,我们可以定义几个变量:
static void Main(string[] args)
{
string name1,name2;
name2="welpher";
name1="伟锋";
GreetPeople(name2,EnglishGreeting);
GreetPeople(name1,ChineseGreeting);
Console.ReadKey();
}
参数string可以这样子定义,那么GreetingDelegate是不是也可以这么用呢?答案是肯定的:
static void Main(string[] args)
{
GrettingDelegate delegate1,delegate2;
delegate1 = EnglishGreeting;
delegate2 = ChineseGreeting;
GreetPeople("welpher",delegate1);
GreetPeople("伟锋",delegate2);
Console.ReadKey();
}
这种定法也会如预料的那样输出。委托不同于string的特性:可以多个方法赋给同一个委托,或者将多个方法绑定到一个委托,当调用这个委托的时候,将依次调用其所绑定的方法,语法如下:
static void Main(string[] args)
{
GreetingDelegate delegate1;
delegate1 = EnglishGreeting;
delegate1 += ChineseGreeting;
//将先后调用 EnglishGreeting和ChineseGreeting方法
GreetPeople("welpher",delegate1);
Console.ReadKey();
}
还可以绕过GreetPeople方法,直接通过委托来调用EnglishGreeting和ChineseGreeting:
static void Main(string[] args)
{
GreetingDelegate delegate1;
delegate1 = EnglishGreeting;
delegate1 += ChineseGreeting;
delegate1("welpher");
Console.ReadKey();
}
上面这些写法,都可以概括为:声明委托,然后声明方法。下面介绍一下匿名的写法:
static void Main(string[] args)
{
GreetingDelegate delegate1 = delegate(string name)
{
Console.WriteLine("你好, "+name);
}
delegate1("伟锋");
}
这已经比较简单了,不用声明方法,用匿名方法就行了,还有更简单的,拉姆达表达式写法:
static void Main(string[] args)
{
GreetingDelegate delegate1 = (m => {Console.WriteLine("你好,"+m);});
delegate1("伟锋");
}
简单的写法肯定很多地方都在用,所以知道这种写法,再也不用看到这种东西而傻眼了。
到这里,想必是对委托有了一定的了解了。未完等续。
参考:
1、http://www.cnblogs.com/jimmyzhang/archive/2007/09/23/903360.html