当一提到委托的时候,大家都会想到委托和事件这两个让人头疼的词语。学习本来就不是一个容易的过程,既然这两者难,我们慢慢地一个一个地学习,相信学到最后你就会爱上它们。
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。(百度百科中的解释http://baike.baidu.com/link?url=y4JTjZL7fHI94wssEb9yxDeMa7972w2L9sNRMpWv04Hi-1sxyU3q2IftNKUdnaI1nB54AKCYq7yHkUklrNPkMmxSceLd5Mz16RNZ8pzlAgu)
定义委托的语法:delegate 方法的返回值类型委托名([方法的参数表]);
例如:publicdelegatevoid GreetingDelegate(string name);
解释:1、Delegate是委托的定义关键字;2、判断一个方法与一个委托是否兼容,主要看其参数表和返回类型(参数表的参数个数顺序类型以及参数的修饰符要一致,返回类型要相同);3、通过委托可以实现对具有相同方法原型的方法进行调用,而不用具体了解其方法的名称。
说委托是一个类,是从委托的声明类似于类这方面来理解的;说委托类似于回调函数,是从委托的作用来理解的。这些理解是人们为了理解委托,而给委托的一种描述,其实,委托就是我们汉语理解中的委托,将一个方法通过委托关联另一个方法,让这两者产生联系,耦合性减小。
通过实例来理解委托。
不使用委托的情况
我们做一个加减法的运算和输出结果的代码:
namespace NoDelegate
{
class Program
{
//加法运算
public static int AddOpen(int a, int b)
{
return a + b;
}
//减法运算
public static int SubOpen(int a, int b)
{
return a - b;
}
public enum Operate
{
Add, Sub
}
//结果
public static int PeopleResult(int a, int b, Operate oper)
{
int result = 0;
switch(oper)
{
case Operate.Add:
result = AddOpen(a, b);
break;
case Operate.Sub:
result = SubOpen(a, b);
break;
}
return result;
}
static void Main(string[] args)
{
Console.WriteLine("最终相加结果是:" + PeopleResult(4,3,Operate.Add));
Console.WriteLine("最终相减结果是:" + PeopleResult(4,3,Operate.Sub));
Console.Read();
}
}
}
如果再加一个乘法运算,就需要修改PeopleResult类和枚举,这样就违背了“开放-封闭原则”,不是好的代码。如果加上委托会怎么样呢?
将委托作为方法的参数类型
引入委托,传入参数,并将委托作为传入的参数的数据类型:
namespace Delegate
{
//定义委托
public delegate int GenericFun(int a,int b);
class Program
{
//加法运算
public static int AddOpen(int a, int b)
{
return a + b;
}
//减法运算
public static int SubOpen(int a, int b)
{
return a - b;
}
//结果
public static int PeopleResult(GenericFun action, int a, int b)
{
int result = action(a, b);
return result;
}
static void Main(string[] args)
{
Console.WriteLine("最终相加结果是:" + PeopleResult(AddOpen, 4, 3));
Console.WriteLine("最终相减结果是:" + PeopleResult(SubOpen, 4, 3));
Console.Read();
}
}
}
在这种情况下,很明显会发现,PeopleResult类里面没有了switch语句,正好应验了文章开头引用的百度百科中的语句—委托可以避免在程序中大量使用If-Else(Switch)语句。对比没有使用委托的例子,同样,想一下,如果加入一个乘法的运算,只需要加一个乘法的类,而不需要再去修改PeopleResult类了,符合“开放-封闭原则”,使程序具有很好地扩展性。
将方法绑定到委托
看一下另一种加入委托的方法:
namespace Delegate
{
//定义委托
public delegate int GenericFun(int a, int b);
class Program
{
//加法运算
public static int AddOpen(int a, int b)
{
return a + b;
}
//减法运算
public static int SubOpen(int a, int b)
{
return a - b;
}
//结果
public static int PeopleResult(GenericFun action, int a, int b)
{
int result = action(a, b);
return result;
}
static void Main(string[] args)
{
GenericFun func = new GenericFun(AddOpen); //绑定加法运算方法
Console.WriteLine("最终相加结果是:" + PeopleResult(func, 4, 3));
func += SubOpen; //绑定减法运算方法
Console.WriteLine("最终相减结果是:" + PeopleResult(func, 4, 3));
Console.Read();
}
}
}
在声明委托类型或基于委托类型的变量时并不指定委托将要调用哪些方法,而是在创建委托的实例时指定,并且在运行时还可以将一个或多个方法与委托动态关联,“+=”就是动态地将另一个方法与委托关联,相反,“-=”是移除委托实例的操作。
拓展
委托的特点:
1、委托类似于C++函数指针,但它是类型安全的。
2、委托允许将方法作为参数进行传递。
1、 委托可用于定义回调方法。
2、 委托可以链接在一起,例如,可以对一个事件调用多个方法。
3、 方法不需要与委托签名精确匹配。
使用委托应注意以下几点:
1、 创建委托所使用的方法必须和委托声明相一致(参数列表、返回值都一致)。
2、 利用+=、-=来进行委托的链接、取消链接或直接使用Delegate.Combine和Delegate.Remove方法来实现。
3、 可以使用MulticastDelegate的实例方法GetInvocationList()来获取委托链中所有的委托。
4、 不能撰写包含out参数的委托。
委托的好处:
1、 确保类型安全;
2、 按序调用多个方法;
3、 支持调用静态方法和实例方法;
4、使用委托可以很多好地分割分层分布架构中的功能分割,对于底层的核心处理方法用户没有必要知道,通过委托访问就可以了。
委托在开发中的用途:
启动线程;通用类库;事件。
讲到委托必然会联想到事件,敬请期待下篇!
小编有话说:可能大家会觉得我写的这个例子不太好,大家可能会想,可以直接在客户端调用加法和减法就行,这样更简单。确实如此。但为了解释委托,我在加法、减法和客户端输出结果之间加了一个PeopleResult类。大家可以将这个类想象成人,人要进行加减法运算,需要使用计算器进行加减法运算。