这两天看了一下C#的东西,最开始准备学习一下LINQ,结果发现里面提到的Lambda表达式不熟悉,转到Lambda表达式,又发现里面提到Delegate(委托),又不太清楚,汗!看来学新东西也要有老东西的扎实基础才行。于是转向了Delegate(委托)。其中发现Delegate(委托)也不简单,也有其发展的曲折历程,下面详细来说。
委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值,如下面的示例所示:
与委托的签名(由返回类型和参数组成)匹配的任何方法都可以分配给该委托。这样就可以通过编程方式来更改方法调用,还可以向现有类中插入新代码。只要知道委托的签名,便可以分配自己的委托方法。
将方法作为参数进行引用的能力使委托成为定义回调方法的理想选择。例如,可以向排序算法传递对比较两个对象的方法的引用。分离比较代码使得可以采用更通用的方式编写算法。
委托是事件的基础。
通过将委托与命名方法或匿名方法关联,可以实例化委托。有关更多信息,请参见命名方法和匿名方法。
上面是MSDN关于委托的一些说明,如果您还不了解委托的意义和基本使用,可以点击上文中的链接。
PS:我所认为的委托就和现实中的委托差不多。比如我要委托一个人去帮我做某件事,这里有两种可以委托的人,A和B,A可以做a1,a2,a3...这些事情,B可以做b1,b2,b3...这些事情,所以我如果要委托某人做ax(x为1,2,3..)这样的事情,我一定会找一个是A的人(就好像我不能指望一个司机去帮我开飞机),告诉他具体去帮我做某一样事情。这就和程序中我找到一个和我需要使用的函数签名相同的代理,然后把具体调用哪个函数传递给它,然后由它代办。
到了C# 3.0版本,实例化委托的方式又多了一种,那就是Lambda表达式,下面我综合了一下这三种方式
{
// Define the delegate
// 定义委托
delegate void Del( string s);
class Program
{
static void Main( string [] args)
{
Del del;
// C# 1.0
// The delegate instantiation using a named method "DoWork":
// 用一个命名方法声明一个委托
del = new Del(DoWork);
// Results from the old style delegate call:
// 老式委托调用方法的结果
del( " The delegate using the named method is called. " );
// C# 2.0
// The delegate instantiation using an anonymous method:
// 用匿名方法声明一个委托
del = delegate ( string s)
{
System.Console.WriteLine(s);
};
// Results from the anonymous delegate call:
// 使用匿名方法的委托的调用结果
del( " The delegate using the anonymous method is called. " );
// C# 3.0
// 用Lambda表达式声明一个委托
del = s => { System.Console.WriteLine(s); };
// 使用Lambda表达式的委托的调用结果
del( " The delegate using lambda expressions is called. " );
}
static void DoWork( string s)
{
System.Console.WriteLine(s);
}
}
}
运行结果
The delegate using the named method is called.
The delegate using the anonymous method is called.
The delegate using lambda expressions is called.
可以看到,上面三种方式的委托都是成功的。
在C# 2.0以前,为了实例化一个委托,我们需要额外定义一个方法,就如上面的DoWork方法。假如这个方法并不通用,仅仅用那么一次,单独定义一个方法出来就显得小题大做了,而且增加了代码的复杂程度。
从C# 2.0开始,引入了匿名方式实例化委托的方式,方法体直接跟在实例化语句之后,方法没有名称,所以称之为匿名方法。另一个区别就是在C# 2.0以前,我们需以new关键字显式创建封装委托
而在从C# 2.0开始,我们只需要这样写(假设我们还用命名方法)
这样感觉直观、舒服了不少。
从C# 3.0开始,又引入了Lambda表达式,可以看到,它用一个神奇的=>符号又简化了表达。当然,这个例子里面简化的似乎不多,但随着您对他的了解深入,一定会感觉到它的方便之处。
也许有人会奇怪为什么我们在IDE生成的事件代码中看到的是这样
它用了 += ,而上面的文章中就用了= 同样也可以相应事件。这涉及到一个合并委托(多路广播委托)的概念。
委托对象的一个用途在于,可以使用 + 运算符将它们分配给一个要成为多路广播委托的委托实例。组合的委托可调用组成它的那两个委托。只有相同类型的委托才可以组合。- 运算符可用来从组合的委托移除组件委托。
看一个MSDN上面的例子可能就非常清楚明了了:
class TestClass
{
static void Hello( string s)
{
System.Console.WriteLine( " Hello, {0}! " , s);
}
static void Goodbye( string s)
{
System.Console.WriteLine( " Goodbye, {0}! " , s);
}
static void Main()
{
Del a, b, c, d;
// Create the delegate object a that references
// the method Hello:
a = Hello;
// Create the delegate object b that references
// the method Goodbye:
b = Goodbye;
// The two delegates, a and b, are composed to form c:
c = a + b;
// Remove a from the composed delegate, leaving d,
// which calls only the method Goodbye:
d = c - a;
System.Console.WriteLine( " Invoking delegate a: " );
a( " A " );
System.Console.WriteLine( " Invoking delegate b: " );
b( " B " );
System.Console.WriteLine( " Invoking delegate c: " );
c( " C " );
System.Console.WriteLine( " Invoking delegate d: " );
d( " D " );
}
}
输出:
Invoking delegate a: Hello, A! Invoking delegate b: Goodbye, B! Invoking delegate c: Hello, C! Goodbye, C! Invoking delegate d: Goodbye, D!
由于IDE并不知道我们那个事件需要有几个响应者,所以它用 += ,这样保证每一个订阅了事件的响应者都能接收到事件的通知,如果用 = ,那么只有最后一个订阅该事件的响应者才能接收到通知了。
--Over--