版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
.net课程系列C#高级编程.NET方向
第二学期课程第三章委托、lambda表达式和事件Newture新程教育声明和使用委托lambda表达式和委托启用事件通知本章目录委托(delegate)是指向一个方法的指针,通过指定一个委托名称,即可通过委托来调用方法。调用委托时,“运行时”实际执行的委托所引用的方法。可动态地更改一个委托引用的方法,使调用一个委托的代码每次都运行一个不同的方法。为了理解委托,最好的办法就是实际的体验它,我们看下面的例子:声明和使用委托为一间工厂写一个控制系统:工厂包含大量不同的机器,工厂在生产产品的时候,每台机器都负责执行不同的任务——切割和折叠金属片、将金属片焊接到一起,印刷金属片等。每台机器都有一家专业厂商制造和安装。机器均由计算机控制,每个厂商都提供一套API;可以利用这些API来控制这些机器。任务是将机器使用的不同的系统集成到一个控制程序中。作为这个控制程序的一部分,你决定提供一个机制,以便在必要的时候快速的关闭所有的机器。API(ApplicationProgrammingInterface),它代表由软件公司开发的一个或一组方法,可通过他们对软件进行控制。可以将.NETFramework想象成一套强大、功能丰富的API。利用它提供的方法,可以控制.NETCLR和操作系统。声明和使用委托每台机器都有它自己的、由计算机控制的过程来实现安全关机。具体方法如下:StopFolding();//折叠和切割机FinishWelding();//焊接机PaintOff();
//彩印机声明和使用委托不使用委托来实现工厂:声明和使用委托classController
{
//代表不同机器的字段privateFoldingMachinefolder;privateWeldingMachinewelder;privatePaintingMachinepainter;
publicvoidShutDown()
{folder.StopFolding();welder.FinishWelding();painter.PaintOff();
}
}虽然这种方法可行,但扩展性和灵活性都不是很好。如果工厂采购了新机器,就必须修改这些代码,因为Controller类和机器是紧密联系在一起的。使用委托来实现工厂:通过观察发现,虽然每个方法的名称不同,但他们都具有相同的“形式”:它们都不获取参数,也都不返回一个值。所以,每个方法的常规形式如下:voidmethdName();这正是委托发挥作用的时候,使用与这种形式匹配的一个委托(delegate),就可以引用任何机器关机方法:
delegatevoidstopMachineryDelegate();委托可以理解为一组“抽象”的方法。声明和使用委托声明委托注意几点:声明委托时,要使用delegate关键字委托定义了它能引用的方法的“形式”。要指定返回类型、委托名、以及参数列表。定义好委托之后,就可以创建它的一个实例,并使用+=操作符,让这个实例引用一个相匹配的方法。声明和使用委托classController
{
delegatevoidstopMachineryDelegate();//定义委托privatestopMachineryDelegatestopMachinery;//定义委托的一个实例publicController()
{this.stopMachinery+=folder.StopFolding;//将方法加到委托中this.stopMachinery+=welder.FinishWelding;//将方法加到委托中this.stopMachinery+=painter.PaintOff;//将方法加到委托中
}
}//如果委托包含了多个方法调用,这种委托就被称为多播委托。可以安全地将+=操作符用在一个未初始化的委托上。该委托自动初始化。还可以使用new关键字显式的初始化一个委托,让它引用一个特定的方法,例如:
this.stopMachinery=newstopMachineryDelegate(folder.StopFolding);通过调用委托来调用它引用的方法,例如:
委托的调用语法与方法完全相同。如果委托引用的方法要获取任何参数,那么应在此时指定。声明和使用委托publicvoidShutDown()
{
this.stopMachinery();//调用委托
}委托的主要优势在于它能引用多个方法;使用+=操作符把这些方法添加到委托中即可。在Controller类的ShutDown方法中调用stopMachinery(),将自动地、依次的调用每一个方法。ShutDown方法不需要知道具体有多少台机器,也不需要知道方法名。使用-=操作符,则可以从委托中移除一个方法:
this.stopMachinery-=StopFolding;声明和使用委托我们当前的方案是在Controller类的构造器中,将机器的关机方法添加到委托中。为了使Controller完全独立于各种机器,需要使用stopMachineryDelegate成为public,并提供一种方式允许Controller外部的类向委托添加方法。有几种方式:将委托变量stopMachinery声明为public保持stopMachinery委托变量为private,但提供一个可读可写属性。通过实现单独的Add和Remove方法来提供完全的封装性。声明和使用委托publicvoidAdd(stopMachineryDelegatestopMethod){this.stopMachinery+=stopMethod;}publicvoidRemove(stopMachineryDelegatestopMethod){this.stopMachinery-=stopMethod;}使用委托时,委托引用的一组方法,必须具有相同的返回类型和参数列表。但是实际情况复杂多变,假定StopFolding方法的签名实际是:
voidStopFolding(intshutDownTime);//在指定的秒数后关机
它的签名区别于FinishWelding和PaintOff方法,所以不能再拿同一个委托处理全部三个方法。问题到了这里怎么处理?lambda表达式和委托解决方案一:创建方法适配器所谓适配器(adapter):指的是一个特殊的方法,它能转换(或者说”适配”)一个方法,为它提供一个不同的签名。比如:然后,再将FinishFolding方法添加到stopMachinery委托中:
this.stopMachinery+=FinishFolding;lambda表达式和委托voidFinishFolding(){folder.StopFolding(0);}解决方案二:lambda表达式lambda表达式是能返回一个方法的表达式。一个典型的方法由4个元素构成:返回类型、方法名、参数列表和方法体。但lambda表达式只包含两个元素:参数列表和方法主体。lambda表达式没有定义方法名,返回类型则从使用lambda表达式的上下文推导。对于StopFolding方法,现在的问题在于它需要一个参数,所以需要创建一个不获取任何参数的适配器,并把这个适配器添加到stopMachinery委托中。可以使用以下语句达到目的:
this.stopMachinery+=(()
=>{folder.StopFolding(0);});lambda表达式和委托参数列表方法主体+=操作符右侧的所有文本就是一个lambda表达式,它定义了要添加到stopMachinery委托的方法。其语法如下:封闭在圆括号内的参数列表。和普通方法一样,即使要定义的方法不获取任何参数,仍然要提供一对圆括号。=>操作符,读作”goesto”,它向编译器指出这是一个lambda表达式。方法主体。和普通方法一样,每个语句都要以一个分号结束。(lambda表达式的主体可以是包含多个语句的一个方法主体,也可以是一个表达式。如果lambda表达式的主体只包含一个表达式,就可以省略{}和一个分号,如下所示:this.stopMachinery+=(()=>StopFolding(0););调用stopMachinery委托时,实际会运行由lambda表达式定义的代码。lambda表达式和委托lambda表达式的形式,需要用心的体会每种形式的区别:x=>x*x;//一个简单表达式,返回参数值的平方,参数x的类型根据上下文推导。x=>{returnx*x;}//语义和上一个表达式相同,但是将一个C#语句块用作主体。()=>folder.StopFolding(0)//调用一个方法,表达式不获取参数,表达式可能会、也可能不会返回值(x,y)=>{x++;returnx/y;}//多个参数;编译器自己推导参数类型,参数x是以值的形式传递,所以++操作的效果是局部于表达式。(refintx,inty)=>{x++;returnx/y;}//多个参数,都显式指定类型,参数x是以引用形式传递,所以++操作的效果是永久的。lambda表达式和委托lambda表达式的一些特点:如果lambda表达式要获取参数,要在=>操作符左侧圆括号内指定它们。可以省略参数类型,C#编译器能根据lambda表达式的上下文来推导。lambda表达式可以返回值,但返回类型必须与即将添加这个lambda表达式的委托类型匹配。lambda表达式的主体可以是一个简单的表达式,也可以是一个C#代码块。lambda表达式方法中定义的变量是局部变量。lambda表达式可以访问和修改lambda表达式外部的所有变量,只要那些变量在lambda表达式定义时,和lambda表达式处在相同的作用域中。lambda表达式和委托虽然委托允许间接调用任意数量的方法,但任然必须显式的调用委托。很多时候,我们需要在发生某件事时,让委托自动运行。例如,在自动化工厂的例子里,假如一台机器过热,就应该自动调用stopMachinery委托来关闭设备。.NETFramework提供了事件(event),可以定义并捕捉特定的事件,并安排调用委托来处理发生的事件。在开发Windows窗体应用程序的时候用到大量的事件,当然我们还可以声明自己的事件。启用事件通知事件的要素:启用事件通知声明一个事件时,采取的方式与声明一个字段非常相似,然而事件设计是随同委托使用的,所以事件的类型必须是一个委托,而且必须在声明前附加event关键字做前缀:
eventdelegateTypeNameeventNamedelegateTypeName:委托类型名称eventName:事件名称classTemperatureMonitor
{publicdelegatevoidStopMachineryDelegate();//定义委托
publiceventStopMachineryDelegateMachineOverheating;//定义事件
……
}订阅事件:把方法添加到一个事件中,这个过程称为订阅事件或者向事件登记——而不是添加到事件基于的那个委托中。使用+=操作符来订阅一个事件:MachineOverheating事件运行时,它将调用所有订阅了这个事件的方法,从而关闭机器。启用事件通知TemperatureMonitortempMonitor=newTemperatureMonitor();tempMonitor.M
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年佛山科学技术学院马克思主义基本原理概论期末考试笔试题库
- 江西鹰潭市某集团行政办公楼设计
- 康复技术物理治疗
- 照明设备采购方案
- 信托产品代销合作协议
- 应急设备管理培训课件
- 2026年期货合约期权居间服务合同
- 搜索引擎优化2026年外包合同协议
- 应急局安全培训方案课件
- 企业档案管理制度
- 2025年新北师大版数学七年级下册全册教案
- DB51T 3115-2023 四川省政务服务评价数据汇聚规范
- (新疆一模)2025届高三高考适应性检测分学科第一次模拟考试 地理试卷(含答案解析)
- 幼儿园绘本故事《三只小猪盖房子》教学课件全文
- JJF(京) 151-2024 药物溶出度仪温度参数校准规范
- 调解实操指南:成为金牌调解员-笔记
- GB/T 27604-2024移动应急位置服务规则
- 苏教译林版五年级上册英语第八单元Unit8《At Christmas》单元测试卷
- 《合同能源管理介绍》课件
- 电力系统继电保护教案
- GB/T 43316.3-2023塑料耐环境应力开裂(ESC)的测定第3部分:弯曲法
评论
0/150
提交评论