当前位置:文档之家› 第三章 委托、lambda表达式和事件

第三章 委托、lambda表达式和事件


void methdName();
这正是委托发挥作用的时候,使用与这种形式匹配的一个委托(delegate),
就可以引用任何机器关机方法:
delegate void stopMachineryDelegate(); 委托可以理解为一组“抽象”的方法。
声明和使用委托
声明委托注意几点:
class Controller 声明委托时,要使用 delegate关键字 { 委托定义了它能引用的方法的“形式”。要指定返回类型、委托名、以及参数列 delegate void stopMachineryDelegate(); //定义委托 表。 private stopMachineryDelegate stopMachinery; //定义委托的一个实例
delegateTypeName:委托类型名称
public delegate void StopMachineryDelegate(); //定义委托 eventName :事件名称 public event StopMachineryDelegate MachineOverheating; //定义事件 …… }
方法主体。和普通方法一样,每个语句都要以一个分号结束。( lambda表达式的 主体可以是包含多个语句的一个方法主体,也可以是一个表达式。如果lambda表 达式的主体只包含一个表达式,就可以省略{}和一个分号,如下所示: this.stopMachinery += (() => StopFolding(0);); 调用stopMachinery 委托时,实际会运行由lambda表达式定义的代码。
lambda表达式和委托
使用委托时,委托引用的一组方法,必须具有相同的返回类型和参数列表。 但是实际情况复杂多变,假定StopFolding方法的签名实际是: void StopFolding(int shutDownTime);//在指定的秒数后关机
它的签名区别于FinishWelding和PaintOff方法,所以不能再拿同一个委托处理
定义好委托之后,就可以创建它的一个实例,并使用+=操作符,让这个实例 引用一个相匹配的方法。 public Controller()
{
this.stopMachinery += folder.StopFolding; //将方法加到委托中 this.stopMachinery += welder.FinishWelding; //将方法加到委托中 this.stopMachinery += painter.PaintOff; //将方法加到委托中
通过调用委托来调用它引用的方法,例如:
public void ShutDown() { this.stopMachinery(); //调用委托 }
委托的调用语法与方法完全相同。如果委托引用的方法要获取任何参数,那 么应在此时指定。
声明和使用委托
委托的主要优势在于它能引用多个方法;使用+=操作符把这些方法添加到委 托中即可。 在Controller类的ShutDown方法中调用stopMachinery(),将自动地、依次的调
全部三个方法。 问题到了这里怎么处理?
lambda表达式和委托
解决方案一:创建方法适配器
为它提供一个不同的签名。比如: void FinishFolding() { folder.StopFolding(0); } 然后,再将FinishFolding方法添加到stopMachinery委托中: this.stopMachinery += FinishFolding;
声明和使用委托
每台机器都有它自己的、由计算机控制的过程来实现安全关机。具体方法如 下:
StopFolding(); PaintOff(); //折叠和切割机 //彩印机 FinishWelding(); //焊接机
声明和使用委托
不使用委托来实现工厂:
class Controller { //代表不同机器的字段 private FoldingMachine folder; private WeldingMachine welder; private PaintingMachine painter; public void ShutDown() { folder.StopFolding(); welder.FinishWelding(); painter.PaintOff(); } }
启用事件通知
虽然委托允许间接调用任意数量的方法,但任然必须显式的调用委托。很多 时候,我们需要在发生某件事时,让委托自动运行。例如,在自动化工厂的 例子里,假如一台机器过热,就应该自动调用stopMachinery委托来关闭设备。
.NET Framework提供了事件(event),可以定义并捕捉特定的事件,并安排调用
式:
public void Add(stopMachineryDelegate stopMethod) 将委托变量 stopMachinery声明为public { 保持 stopMachinery委托变量为 private,但提供一个可读可写属性。 this.stopMachinery += stopMethod; } 通过实现单独的Add和Remove方法来提供完全的封装性。 public void Remove(stopMachineryDelegate stopMethod) { this.stopMachinery -= stopMethod; }
所谓适配器(adapter):指的是一个特殊的方法,它能转换(或者说”适配”)一个方法,
lambda表达式和委托
解决方案二: lambda表达式
lambda表达式是能返回一个方法的表达式。
一个典型的方法由4个元素构成:返回类型、方法名、参数列表和方法体。但 lambda表达式只包含两个元素:参数列表和方法主体。 lambda表达式没有定义方法名,返回类型则从使用lambda表达式的上下文推导。 对于StopFolding方法,现在的问题在于它需要一个参数,所以需要创建一个不获取 任何参数的适配器,并把这个适配器添加到stopMachinery委托中。可以使用以下 语句达到目的: this.stopMachinery += (() => {folder. StopFolding(0); });
虽然这种方法可行,但扩展性和灵活性都不是很好。如果工厂采购了新机器, 就必须修改这些代码,因为Controller类和机器是紧密联系在一起的。
声明和使用委托
使用委托来实现工厂: 通过观察发现,虽然每个方法的名称不同,但他们都具有相同的“形式”: 它们都不获取参数,也都不返回一个值。所以,每个方法的常规形式如下:
}
} //如果委托包含了多个方法调用,这种委托就被称为多播委托。
声明和使用委托
可以安全地将+=操作符用在一个未初始化的委托上。该委托自动初始化。还 可以使用new关键字显式的初始化一个委托,让它引用一个特定的方法,例如: this.stopMachinery = new stopMachineryDelegate(folder.StopFolding);
用每一个方法。 ShutDown方法不需要知道具体有多少台机器,也不需要知道
方法名。 使用-=操作符,则可以从委托中移除一个方法: this.stopMachinery -= StopFolding;
声明和使用委托
我们当前的方案是在Controller类的构造器中,将机器的关机方法添加到委托 中。为了使Controller完全独立于各种机器,需要使用stopMachineryDelegate成 为public,并提供一种方式允许Controller外部的类向委托添加方法。有几种方
不同的方法。
为了理解委托,最好的办法就是实际的体验它,我们看下面的例子:
声明和使用委托
为一间工厂写一个控制系统:
工厂包含大量不同的机器,工厂在生产产品的时候,每台机器都负责执行不同的 任务——切割和折叠金属片、将金属片焊接到一起,印刷金属片等。 每台机器都有一家专业厂商制造和安装。机器均由计算机控制,每个厂商都提供 一套API;可以利用这些API来控制这些机器。 任务是将机器使用的不同的系统集成到一个控制程序中。作为这个控制程序的一
lambda表达式和委托
lambda表ห้องสมุดไป่ตู้式的一些特点:
如果lambda表达式要获取参数,要在=>操作符左侧圆括号内指定它们。可以省略
参数类型,C#编译器能根据lambda表达式的上下文来推导。 lambda表达式可以返回值,但返回类型必须与即将添加这个lambda表达式的委托 类型匹配。 lambda表达式的主体可以是一个简单的表达式,也可以是一个C#代码块。 lambda表达式方法中定义的变量是局部变量。 lambda表达式可以访问和修改lambda表达式外部的所有变量,只要那些变量在 lambda表达式定义时,和lambda表达式处在相同的作用域中。
部分,你决定提供一个机制,以便在必要的时候快速的关闭所有的机器。
API(Application Programming Interface),它代表由软件公司开发的一个或一 功能丰富的API。利用它提供的方法,可以控制.NET CLR和操作系统。
组方法,可通过他们对软件进行控制。可以将.NET Framework想象成一套强大、
委托来处理发生的事件。 在开发Windows窗体应用程序的时候用到大量的事件,当然我们还可以声明自 己的事件。
启用事件通知
事件的要素:
class TemperatureMonitor
{
声明一个事件时,采取的方式与声明一 个字段非常相似,然而事件设计是随同 委托使用的,所以事件的类型必须是一 个委托,而且必须在声明前附加event 关键字做前缀: event delegateTypeName eventName
相关主题