C#2008与.NET 3.5 高级程序设计读书笔记(11)-- 委托、事件和Lambda
1.委托
(1)委托的定义
《高级汉语大词典》中是如下解释的:托付给别的人或机构办理。要说生活中的意思其实大家都能理解,无非是“当某人(机构)需要完成一件自己不能或不应该完成的事情的时候,此人(机构)物色一个合适的且有能力完成此事的人选,然后提供必要的信息,将此事委托给物色到的人(机构)来完成。”
软件的对象方法其实是对现实世界的模拟,你可能会想现实世界里的委托哪有这么多呢?这么重要呢?其实你也许没有注意到老板把厚厚的一摞资料摔在你的案头让你无论如何在×月×日前交活,这不就是一种委托吗?当然也许没有委托书(和委任状),但它就是委托。这样看委托是不是就非常重要了,它甚至是构成现实社会的基础机制之一。
从这个意义上理解委托机制的重要性我想应该是足够了。委托机制是促使事件发送与事件接受的一种对接策略,对象对周围信号的反应或在一定环境中所具备的对其它对象的通知行为的响应则被描述成所谓的“事件”,这可以类比人对周围世界反馈产生信号的能力。
委托就是一种定向信号流:指定产生、接受信号者并产生信号反馈的技术。
我可爱的小女儿才刚刚学会说话就在饭桌上支使她可怜的“老”爸:爸爸,把我的小勺子拿来。我接到“信号”立即屁颠屁颠地跑到厨房拿到勺子送到女儿的小手上,一个“委托”完成的非常漂亮,而女儿则无须知道我在什么地方、如何拿到勺子,她只管接受到我给她专门买的小勺子就行,否则,她就要仰着小脸“哇哇”大哭了。
C#中的委托是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为,委托方法的使用可以像其他任何方法一样具有参数和返回值。委托对象能被传递给调用该方法引用的代码而无须知道哪个方法将在编译时被调用。委托是函数的封装,它代表一“类”函数。他们都符合一定的签名:拥有相同的参数列表、返回值类型。同时委托也可以看作是对函数的抽象,是函数的“类”。此时,委托实例代表一个具体的函数。委托应该和类同属一个层面,使用起来也很象一个类。
最通俗易懂的话来讲,你就可以把委托看成是用来执行方法(函数)的一个东西。
(2)委托的使用
namespace Vczx.ProCSharp.Exc
{
//步骤一:声明委托
delegate double MathsOp( double x );
class Start
{
public class MyDelegate
{
public static double MultiplyBy2( double x )
{
return x * 2;
}
}
[STAThread]
static void Main(string[] args)
{
//步骤二:实例化委托
MathsOp operation = new MathsOp( MyDelegate.MultiplyBy2 );
double x = 1.23;
//步骤三:调用委托
double result = operation( x );
Console.WriteLine( "{0} multiply by 2 is {1}", x, result );
Console.Read();
}
}
}
(3)多路广播委托
前面使用的委托只包含一个方法调用。调用委托的次数与调用方法的次数相同。如果要调用多个方法,就需要多次显示调用这个委托。其实委托也可以包含多个方法,这种委托就是多路广播委托。多路广播委托派生于System.MulticastDelegate,它的Combine方法允许把多个方法调用链接在一起,我们可以通过+=来向委托添加调用方法,也可以用-=删除其中的调用方法。如
namespace Vczx.ProCSharp.Exc
2{
3 public class MyDelegate
4 {
5 public static void MultiplyBy2( double value )
6 {
7 double result = value * 2;
8 Console.WriteLine( "Multiplying by 2: {0} gives {1}", value, result );
9 }
10
11 public static void Squre( double value )
12 {
13 double result = value * value;
14 Console.WriteLine( "Squaring: {0} gives {1}", value, result );
15 }
16 }
17
18 delegate void MathsOp( double x );
19
20 class Start
21 {
22 [STAThread]
23 static void Main(string[] args)
24 {
25 MathsOp operation = new MathsOp( MyDelegate.MultiplyBy2 );
26 operation += new MathsOp( MyDelegate.Squre );
27 double x = 1.23;
28 operation( x );
29
30 operation -= new MathsOp( MyDelegate.MultiplyBy2 );
31 operation( x );
32
33 Console.Read();
34 }
35 }
36}
(4)委托的好处:
1.相当于用方法作为另一方法参数(类似于C的函数指针)
2.在两个不能直接调用的方法中作为桥梁,如:在多线程中的跨线程的方法调用就得用委托
3.当不知道方法具体实现什么时使用委托,如:事件中使用委托
2.事件
(1)事件的定义
事件就是当对象或类状态发生改变时,对象或类发出的信息或通知。发出信息的对象或类称为"事件源",对事件进行处理的
事件实际上就是委托的实例,因为委托实际上就是一个类.
这个场景可以抽象为委托和事件的几个要素:
猫和老鼠分别是两个对象,猫是激发事件的对象,猫叫是一个方法,同时引发一个事件,老鼠作为事件的处理者,它的处理结果是听到猫叫就逃跑,这样定义一个委托就是表示老鼠对猫的动静的监听。
namespace EventDemo
{
public delegate void CatListeningHandler();
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
Mouse mouse = new Mouse();
//步骤三:监听事件,订阅/关注事件
cat.CatCry += new CatListeningHandler(mouse.Run);
cat.OnCry();
}
}
public class Cat
{
//步骤一:定义事件
public event CatListeningHandler CatCry;
public void OnCry()
{
//步骤二:触发事件
if (CatCry != null)
{
Console.WriteLine("Meow~~");
CatCry();
}
}
}
public class Mouse
{
//步骤四:执行事件
public void Run()
{
Console.WriteLine("猫来了,快逃跑呀");
}
}
}
(2)事件的理解
委托与事件的结合可以更好的降低对象之间的“耦合性”,取生活中的一个场景,孩子饿了,要哭,爸爸妈妈听到哭声都会赶过来。如果按照常规的编程方法,我们可能要在Child类里边实现一个方法来通知爸爸和妈妈,假设有一天这家聚会,爷爷奶奶,姥姥姥爷,姑姑婶婶全过来了,那么孩子必须要通知增加的这些人,我们就不得不修改Child类里的这个方法。
而事实上我们可以这样考虑,将对孩子哭这一事件关心的一类人抽象出来,爷爷奶奶,姥姥姥爷,姑姑婶婶都从该类派生,他们有一个公共的代理,只要他们讲自己的行为“注册”到这个代理,孩子一哭,所有被注册进去的事件就会形成一个事件的链表然后顺次执行。
(3)带有数据的事件
delegate void 事件委托名(object sender,EventArgs e);
sender是事件源
比如说你按下按钮,那么sender就是按钮
又如:textboxchange,sender就是该textbox,在事件处理中就可以用sender代替textbox.
如:
(sender as TextBox).Text="fdsaewfsda";
Winfrom程序当中大部分时候是控件
EventArgs是事件参数
//该事件传入的参数,比如说你用鼠标点击窗体
那么EventArgs是会包含点击的位置等等
它用来辅助你处理事件
EvengHandler 委托 ,会告诉主程序,有一些事情发生了:这个事件是由于object类型的sender 导致的,e就是事件的内容了
using System;
namespace EventDemo
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class EventReceiver
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
EventSender c1 = new EventSender();
//委托实例化后绑定到事件
c1.OnUserRequest += new UserRequest(c1_OnUserRequest);
c1.Run();
}
private static void c1_OnUserRequest(object sender, OnUserRequestEventArgs e)
{//事件处理方法
Console.WriteLine("你触发了事件"+e.InputText);
}
}
//定义委托
public delegate void UserRequest(object sender,OnUserRequestEventArgs e);
/// <summary>
/// 带事件数据的事件类,从EventArgs继承
/// </summary>
public class OnUserRequestEventArgs : System.EventArgs
{
private string _InputText;
public string InputText
{
get
{
return _InputText;
}
set
{
_InputText = value;
}
}
}
/// <summary>
/// 事件发送类
/// </summary>
public class EventSender
{
public EventSender()
{
}
//定义一个委托类型的事件
public event UserRequest OnUserRequest;
public void Run()
{
while(true)
{
if(Console.ReadLine() == "a")
{
//事件监听,产生事件
OnUserRequestEventArgs e = new OnUserRequestEventArgs();
e.InputText = "a";
OnUserRequest(this,e);
}
}
}
}
}