第6章 委托和事件(3)

2020-02-22 11:00

第6章 委托和事件 {

private string name; private decimal salary;

public Employee(string name, decimal salary) {

this.name = name; this.salary = salary; }

public override string ToString() {

return string.Format(name + \ }

public static bool RhsIsGreater(object lhs, object rhs) {

Employee empLhs = (Employee) lhs; Employee empRhs = (Employee) rhs;

return (empRhs.salary > empLhs.salary) ? true : false; } }

? 163 ? 注意,为了匹配CompareOp委托的签名,在这个类中必须定义RhsIsGreater,它的参数是两个对象引用,而不是Employee引用。必须把这些参数的数据类型转换为Employee引用,才能进行比较。

下面编写一些客户机代码,完成排序:

using System;

namespace Wrox.ProCSharp.AdvancedCSharp {

delegate bool CompareOp(object lhs, object rhs);

class MainEntryPoint {

static void Main() {

Employee [] employees = {

new Employee(\ new Employee(\ new Employee(\

new Employee(\ new Employee(\

? 164 ? 第Ⅰ部分 C# 语 言 new Employee(\

CompareOp employeeCompareOp = new CompareOp(Employee.RhsIsGreater); BubbleSorter.Sort(employees, employeeCompareOp);

for (int i=0 ; i

运行这段代码,正确显示按照薪水排列的Employee,如下所示:

BubbleSorter

Elmer Fudd, $10,000.00 Bugs Bunny, $20,000.00 Foghorn Leghorn, $23,000.00 Daffy Duck, $25,000.00 RoadRunner, $50,000.00 Wiley Coyote, $1,000,000.38

6.2.3 多播委托

前面使用的每个委托都只包含一个方法调用。调用委托的次数与调用方法的次数相同。如果要调用多个方法,就需要多次显式调用这个委托。委托也可以包含多个方法。这种委托称为多播委托。如果调用多播委托,就可以按顺序连续调用多个方法。为此,委托的签名就必须返回void(否则,返回值应送到何处?)。实际上,如果编译器发现某个委托返回void,就会自动假定这是一个多播委托。下面的代码取自于SimpleDelegate示例,尽管其语法与以前相同,但实际上它实例化了一个多播委托Operations:

delegate void DoubleOp(double value);

// delegate double DoubleOp(double value); // can't do this now

class MainEntryPoint {

static void Main() {

DoubleOp operations = new DoubleOp(MathOperations.MultiplyByTwo); operations += new DoubleOp(MathOperations.Square);

在前面的示例中,要存储对两个方法的引用,所以实例化了一个委托数组。而这里只是在一个多播委托中添加两个操作。多播委托可以识别运算符+和+=。还可以扩展上述代码中的最后两行,它们具有相同的效果:

DoubleOp operation1 = new DoubleOp(MathOperations.MultiplyByTwo); DoubleOp operation2 = new DoubleOp(MathOperations.Square); DoubleOp operations = operation1 + operation2;

第6章 委托和事件 ? 165 ? 多播委托还识别运算符–和–=,以从委托中删除方法调用。

注意:

根据后面的内容,多播委托是一个派生于System.MulticastDelegate的类,System.Multicast- Delegate又派生于基类System.Delegate。System.MulticastDelegate的其他成员允许把多个方法调用链接在一起,成为一个列表。

为了说明多播委托的用法,下面把SimpleDelegate示例改写为一个新示例MulticastDelegate。现在需要把委托表示为返回void的方法,就应重写MathOperations类中的方法,让它们显示其结果,而不是返回它们:

class MathOperations {

public static void MultiplyByTwo(double value) {

double result = value*2; Console.WriteLine(

\ }

public static void Square(double value) {

double result = value*value;

Console.WriteLine(\ } }

为了适应这个改变,也必须重写ProcessAndDisplayNumber:

static void ProcessAndDisplayNumber(DoubleOp action, double value) {

Console.WriteLine(\ valueToProcess); action(valueToProcess); }

下面测试多播委托,其代码如下:

static void Main() {

DoubleOp operations = new DoubleOp(MathOperations.MultiplyByTwo); operations += new DoubleOp(MathOperations.Square);

ProcessAndDisplayNumber(operations, 2.0); ProcessAndDisplayNumber(operations, 7.94); ProcessAndDisplayNumber(operations, 1.414);

? 166 ? Console.WriteLine(); }

第Ⅰ部分 C# 语 言 现在,每次调用ProcessAndDisplayNumber时,都会显示一个信息,说明它已经被调用。然后,下面的语句会按顺序调用action委托实例中的每个方法:

action(value);

运行这段代码,得到如下所示的结果:

MulticastDelegate

ProcessAndDisplayNumber called with value = 2 Multiplying by 2: 2 gives 4 Squaring: 2 gives 4

ProcessAndDisplayNumber called with value = 7.94 Multiplying by 2: 7.94 gives 15.88 Squaring: 7.94 gives 63.0436

ProcessAndDisplayNumber called with value = 1.414 Multiplying by 2: 1.414 gives 2.828 Squaring: 1.414 gives 1.999396

如果使用多播委托,就应注意对同一个委托调用方法链的顺序并未正式定义,因此应避免编写依赖于以任意特定顺序调用方法的代码。

6.3 事件

基于Windows的应用程序也是基于消息的。这说明,应用程序是通过Windows来通信的,Windows又是使用预定义的消息与应用程序通信的。这些消息是包含各种信息的结构,应用程序和Windows使用这些信息决定下一步的操作。在MFC等库或VB等开发环境推出之前,开发人员必须处理Windows发送给应用程序的消息。VB和今天的.NET把这些传送来的消息封装在事件中。如果需要响应某个消息,就应处理对应的事件。一个常见的例子是用户单击了窗体中的按钮后,Windows就会给按钮消息处理程序(有时称为Windows过程或WndProc)发送一个WM_MOUSECLICK消息。对于.NET开发人员来说,这就是按钮的OnClick事件。

在开发基于对象的应用程序时,需要使用另一种对象通信方式。在一个对象中发生了有趣的事情时,就需要通知其他对象发生了什么变化。这里又要用到事件。就像.NET Framework把Windows消息封装在事件中那样,也可以把事件用作对象之间的通信介质。

委托就用作应用程序接收到消息时封装事件的方式。

在上一节介绍委托时,仅讨论了理解事件如何工作所需要的内容。但Microsoft设计C#事件的目的是为了让用户无需理解底层的委托,就可以使用它们。所以下面开始从客户软件的角度讨论事件,主要考虑的是需要编写什么代码来接收事件通知,而无需担心后台上究竟发生了

第6章 委托和事件 ? 167 ? 什么,从中可以看出事件的处理十分简单。之后,编写一个生成事件的示例,介绍事件和委托之间的关系。

本节的内容对C++开发人员最有用,因为C++没有与事件类似的概念。另一方面,C#事件与VB事件非常类似,但C#中的语法和底层的实现有所不同。

注意:

这里的术语“事件”有两种不同的含义。第一,表示发生了某个有趣的事情;第二,表示C#语言中已定义的一个对象,即处理通知过程的对象。在使用第二个含义时,我们常常把事件表示为C#事件,或者在其含义很容易从上下文中看出时,它就是一个事件。

6.3.1 从客户的角度讨论事件

事件接收器是指在发生某些事情时被通知的任何应用程序、对象或组件。当然,有事件接收器,就有事件发送器。发送器的作用是引发事件。发送器可以是应用程序中的另一个对象或程序集,在系统事件中,例如鼠标单击或键盘按键,发送器就是.NET运行库。注意,事件的发送器并不知道接收器是谁。这就使事件非常有用。

现在,在事件接收器的某个地方有一个方法,它负责处理事件。在每次发生已注册的事件时,就执行这个事件处理程序。此时就要使用委托了。由于发送器对接收器一无所知,所以无法设置两者之间的引用类型,而是使用委托作为中介。发送器定义接收器要使用的委托,接收器将事件处理程序注册到事件中。连接事件处理程序的过程称为封装事件。封装Click事件的简单例子有助于说明这个过程。

首先创建一个简单的Windows窗体应用程序,把一个按钮控件从工具箱拖放到窗体上。在属性窗口中把按钮重命名为btnOne。在代码编辑器中把下面的代码添加到Form1构造函数中:

btnOne.Click += new EventHandler(Button_Click);

在Visual Studio中,注意在输入+=运算符之后,就只需按下Tab键两次,编辑器就会完成剩余的输入工作。在大多数情况下这很不错。但在这个例子中,不使用默认的处理程序名,所以应自己输入文本。

这将告诉运行库,在引发btnOne的Click事件时,应执行Button_Click方法。EventHandler是事件用于把处理程序(Button_Click)赋予事件(Click)的委托。注意使用+=运算符把这个新方法添加到委托列表中。这类似于本章前面介绍的多播示例。也就是说,可以为事件添加多个事件处理程序。由于这是一个多播委托,所以要遵循添加多个方法的所有规则,但是不能保证调用方法的顺序。下面在窗体上再添加一个按钮,把它重命名为btnTwo。把btnTwo的Click事件也连接到同一个Button_Click方法上,如下所示:

btnOne.Click += new EventHandler(Button_Click); btnTwo.Click += new EventHandler(Button_Click);

EventHandler委托已在.NET Framework中定义了。它位于System命名空间,所有在.NET Framework中定义的事件都使用它。如前所述,委托要求添加到委托列表中的所有方法都必须


第6章 委托和事件(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:教师资格证考试中学综合素质考点

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: