16.1.2 使用事件和观测

728 篇文章 1 订阅
16.1.2 使用事件和观测






    到目前为止,我们已经看到两种表示事件的类型,它们之间的关系相当简单: IEvent<'T> 接口继承自 IObservable<'T> 接口。IEvent<'T> 类型更具体,主要用于 F#,表示标准的 .NET 事件,而不是特殊的语言功能。


    我们也看到了用高阶函数处理事件的 Observable 模块。模块中的函数,取 IObservable<'T> 接口值作为参数,但由于 IEvent<'T> 是从继承 IObservable<'T> ,我们也可以使用这些函数处理标准的 F# 事件。为了保持完整性,还有一个 Event 模块,其函数与 Observable 模块中的类似。这些函数的参数只是 IEvent<'T> 类型的值,产生相同的事件值类型。决定使用哪个接口和模块,听起来可能复杂,但我们可以使用四个简单的事实和规则进行决定:


    1、IObservable<T> 有一个方法 Subscribe,它用于注册观察者(observer),当可观察对象的状态更改时,将被调用。


    2、IEvent<T> 添加了几个方法,可能使用常见的编码模式,来处理标准事件。它提供了 Add 方法,很容易注册事件处理程序 AddHandler/RemoveHandler,当我们想要使用委托时,这是非常有用的。


    3、当我们在 F# 中声明 C# 的兼容事件时,可以使用 IEvent<'T> 类型,将在 16.1.5 节中讨论。如果要构建一个事件,使用高阶函数从另一个事件,将需要使用该 Event 模块。


    4、在本章的其余部分,我们会喜欢来自 Observable 的模块,因为这些函数更好地使用 Async.AwaitObservable  基元,在 16.3 节中我们会看到。组合 Event 模块的函数,使用我们稍后将介绍的方法,泄漏(leaks),其中,事件处理程序没有正确地删除。


    现在,我们知道了将主要使用 Observable 模块,看一下表 16.1,展示了这个模块提供了哪些函数。Event 模块的结构很相似,除了类型签名。你可以看到,很多函数与处理序列的函数非常对应。






Table 16.1 Overview of the most important functions of the Observable module






函数
 类型和描述
 
filter
 ('T -> bool) -> IObservable<'T> -> IObservable<'T> 
当源事件发生时,返回被触发的事件,但仅是由这个事件所携带的值匹配指定的断言。这个函数对应于列表的 List.filter。 
map
 ('T -> 'U) -> IObservable<'T> -> IObservable<'U> 




每当源事件触发时,返回被触发的事件,由返回事件所携带的值,使用指定的函数计算源值。对应于 List.map 函数。
 
add
 ('T -> unit) -> IObservable<'T> –> unit


为指定的事件注册回调函数。每当发生该事件时,给定的函数调用。这个函数类似于 List.iter。
 
scan
 ('U -> 'T -> 'U) -> 'U -> IObservable<'T> -> IObservable<'U>


这个函数创建一个有内部状态的事件。初始状态由第二参数值指定,每当源事件使用指定的函数发生时,就更新。返回的事件报告每次源事件被触发时累加的状态,使用源事件的值,重新计算它之后。
 
merge
 IObservable<'T> -> IObservable<'T> -> IObservable<'T>


作为参数传入的不管哪一个事件发生时,创建一个被触发的事件。注意,由事件 ('T) 携带的值的类型,必须与两个事件相同。
 
partition
 ('T -> bool) -> IObservable<'T> 
                     -> IObservable<'T> * IObservable<'T> 




把一个事件拆分为两个不同的事件,基于提供的断言。当输入的事件触发时,partition 函数运行断言,触发两个创建的事件之一,取决于断言的结果。行为对应于 List.partition 函数。
 






    表 16.1 中的大部分函数应该很容易理解,因为,我们已经见过类似的处理列表的函数,唯一的区别是 Observable.scan,它看上去比其他的复杂些。处理列表的也存在 scan 函数,但我们尚未讨论,签名也类似于 List.fold,我们已经知道得很好。


    这两个函数取一个初始状态和一个函数,它知道如何从原始状态计算新的状态,并从由事件所携带的列表或值计算一个元素。不同之处在于,fold 数返回列表的所有元素的累计结果。对事件来说,这是不可能的,因为我们不知道事件最后什么时候发生。不是等待最后一个元素,Observable.scan 函数返回一个触发的事件,每当内部状态重新计算时,计算到目前为止的聚合值。我们会在 16.1.3 节看到这样一个示例函数。


   处理事件使用高阶函数的最大好处,是我们可以用更声明的方式写代码。在我们的示例中,替换一个命令 if,在有筛选器的事件处理程序中,但我们可以看更进一步的示例。如果我们创建一个函数(我们将称它 formatFileEvent),设置由 RenamedEventArgs 所携带的信息的格式,我们可以把整个事件处理写成一个单独的、简洁的表达式,如下所示。






Listing 16.3 Declarative event handling (F#)






fileWatcher.Renamed 
  |> Observable.filter isNotHidden 
  |> Observable.map formatFileEvent 
  |> Observable.add (printfn "%s")






    清单 16.3 实现的功能,与清单 16.2 相同,使用两个辅助函数,和来自 Observable 模块的函数。一旦开始把一个事件当作一系列的值,代码就容易理解了。不用命令式指定当事件发生时应该做什么,而是以声明方式指定所需的结果方面。第一行指定哪种事件是我们感兴趣的,第二行指定哪些信息是重要的,最后一行显示格式化的信息。


    最初,我们从一个携带 RenamedEventArgs 类型值的事件开始。筛选操作不更改类型,在某些情况下,不触发返回的事件。映射可以改变类型,formatFileEvent 函数返回一个字符串值,因此,我们最后的事件包含字符串。这意味着,最后的基元期望的函数,将一个字符串作为参数,并返回 unit。可以看到,可以很容易地创建这样一个函数,使用偏函数应用。带 %s 格式说明符的 printfn 函数,创建了打印给定字符串的函数。


    这种处理事件的方式还带给我们更丰富的方式,将代码拆分为可重用的元素。我们可以省略最后一行,以创建一个事件,可以在应用程序中的其他地方使用。然后,用 Observable.add 与 MessageBox.Show 一起,以图形方式显示通知,用同一个事件追加日志文件。让我们看一个稍微复杂的例子。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值