c# 委托和事件的应用

 

篇首介绍

向公司提出了辞职,等待着业务交接,有些上火……这是我第一次翻译文章,里面有很多不足点,欢迎大家指摘,共同进步。

1介绍

在这篇文章开始时,我们先去理解委托可以去解决什么问题,我们可以创建一个简单的委托去解决问题。然后我们会去理解多播委托和事件怎么去简述委托,最后我们去理解委托和事件的不同点和怎么去异步调用委托。当我们了解了委托和事件的基础后,我们可以总结出来几种重要的委托的应用。

2 方法和函数的抽象问题

在我们向下进行之前,先来讨论一下委托可以解决什么问题

下面有一个只有一个简单的'Add'方法的类'ClsMaths'。这个类作为一个简单的UI。如果过了一段时间后,想要为这个类添加一个减法,那么你的用户为了适应新的方法就必须做出一些调整。换句话说,如果要增加新的方法会导致你重新编译你的UI客户端。

简单来说,就是UI客户端的耦合度比较高,那么我们如何解决这个问题呢,与其在UI里加入实际的方法倒不如,我们放一个虚拟的指针让他来只想我们实际的方法从而减低UI和实际方法的耦合度。不管做任何改变我们都不会影响到UI,也就是说这些改变也不会影响到那些指向他们的指针。像这些抽象的指针我们就可以定义为委托。委托用来定义一个简单的抽象指针去指向方法或者函数。

 

那么现在我们已经理解了这个紧耦合和解决方案,现在让我们去了解怎么定义一个简单的委托。

3 怎么定义一个委托

实现一个委托需要四步:declare,create,point,invoke

第一步是定义一个委托,要求其委托的方法需要和委托有相同的返回值类型和输入参数。像下面这个方法有两个int型的输入参数和一个int型的返回值

所以在这个方法之上的代理就需要按如下的方式定义。(注意委托的关键字)

其输入参数和返回值必须完全一致,如果出现不能匹配的地方会出现像下图一样的错误。

第二步是创建一个委托的引用。

第三步是将委托指向所需引用的方法,在我们的介绍中就是需要将代理指向ADD方法

最后我们需要用委托的Invoke方法去调用该委托

 

下图是对以上四步的总结

4 用委托解决抽象指针的问题

为了降低算法修改所带来的问题我们可以将所有的算法方法通过抽象代理暴露出来

那么第一步我们要做的就是声名一个有两个输入参数和一个返回值的委托,如下所示

下一步是将委托和暴露的方法关联起来。

下面的代码是整个的代码片断。所有的像ADD SUB这些方法全部声名为私有的,只将他们的委托暴露出来以用来调用这些方法。

现在在客户端就可以真正的实现和那些实际的ADD Sub 方法的松耦合

 

5 多播委托

在上面的例子中我们可以看到如何创建一个委托并指向一个方法。

实际上我们可以创建一个委托指向多个方法。当我们调用委托时就会顺序的调用所有的方法。下面的代码片断中就关联了两个方法的委托delegateptr,为了将多个方法加入到一个委托中我们需要使用+=标识。现在如果我们要调用该委托,它会首先调用方法一然后是方法二。调用时按照方法添加到委托的顺序执行。

那么我们怎么讲多播委托应用到实际的工程中呢。大多数时候我们需要创建发布者类型的Model。举例来说,在一个应用中,我们有一系列的常规错误,当这些错误产生时,我们就要将这些错误广播为监视它们的组件

6 多播委托的简单描述

为了更好的理解多播委托,让我们做下面一个demo。在这个demo中,我们有Form1,Form2,Form3。Form1拥有多播委托将事件传递给Form2 Form3

在Form1中我们首先需要定义一个委托,该委托的责任是广播事件给其他的form

在form的load时间中我们将需要委托的方法加入到委托中

最后我们调用和传播方法的调用到各个Form

 

7 多播委托的问题---赤裸裸的暴露

第一个问题是这些描述者(Form2 Form3)并没有权力去说我们对这个事件感不感兴趣,这些全部都决定于‘Form1’当然我们可以走另外一路 i.e.将委托传递给描述者,让他们去添加他们想要从Form1接受到的广播,但是这个会导致新的问题i.e.违反了封装的概念等,如果我们将委托暴露给描述者让他们可以调用委托,添加自己的方法等,换而言之就是这个代理已经完全暴露给描述者。

8 事件--委托的封装

事件可以帮助委托解决封装的问题。事件位于委托的最顶端,提供封装以让目标代码对于委托只拥有监听却没有所有的控制权。

下面几点描述了该问题

   ①方法和函数利用委托进行抽象/封装

   ②委托是用于将来继承自利用多播委托提供事件广播的模型

   ③多播广播利用事件加深了封装

9 事件的实现

下面让我们举些需要使用多播委托的例子,然后使用事件来实现他们。事件在内部使用委托就像事件了委托更高层次的封装。那么第一步,在发布者(Form1)中,我们需要定义一个委托和该委托的事件。下面的代码片断就是该定义(注意事件关键词)

我们定义了一个委托'CallEveryOne',同时我们为这个委托标注了一个事件'EventCallEveryOne'

从发布者来看 i.e. 'Form1' 生成了 'Form2' 'Form3',同时连接了当前的'Form1'以使'Form2' 'Form3'可以监听到事件。当这个object被连接上时,则产生了该事件

作为描述者一方 i.e.(Form2 Form3)将这些方法连接到事件监听

这个可以和上面的多播委托得到相同的结果

10 委托和事件的不同点

事实上,委托和事件的真正不同不只是给事件加上一层糖衣。上面已经介绍了他们主要的不同点就是事件提供了委托更深层次的封装。所以当我们传递委托时,它就会暴露出来,目标/描述者可以修改这个委托。而当我们使用事件时,目标只能监听它。

11 异步的委托调用

另一个委托的应用是方法的异步调用。你可以通过委托异步调用方法。所谓异步调用是指客户端调用这个委托,但是控制器并不直接放回到当前的执行中来。这个委托和主调用并行执行。当这个委托结束了它的工作后回到主调用告诉它该调用已经完成。

想要异步的调用一个委托我们需要调用方法begininvoke,在该方法中我们需要指定回调函数

对于下面的方法CallbackMethod将会在委托执行结束后调用

12 委托应用的总结

这里有5个应用

    ①抽象和封装一个方法(异步调用)

        这个是委托的最重要的应用。它帮助我们定义一个抽象的指针可以指向对应的方法。同

        样的抽象委托可以被用来指向相同类型的方法。在上面的章节中,我们已经展示了一个

        简单的例子,在后续增加算数方法时并不会影响到UI

    ②回调机制

        在很多时候我们都希望可以提供一个回调机制。委托可以将其传递到目的地,然后目的

        地运用相同的委托指针去执行回调

    ③异步处理

        通过使用BeginInvoke和EndInvoke我们可以异步地执行委托,在上面的章节中我们

        已经详细的描述过该应用

    ④广播---序列性的处理

        有时当我们需要按照一定的规则序列性的指向一些方法时可以使用多播委托。上面已经

        介绍过该应用了

    ⑤事件--发布者描述者Model

        我们可以利用事件来创建一个真正的发布者/描述者的模型

13 委托和C++指针的不同

C++指针并不是类型安全的,换而言之,它可以指向任意类型的方法。从另一个角度讲,委托是类型安全的,一个委托可以指向int型的返回值类型却不能指向string型返回值类型

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值