`
tianshibaijia
  • 浏览: 1128780 次
文章分类
社区版块
存档分类
最新评论

16.1.5 在 F# 中声明事件

 
阅读更多

16.1.5 在 F# 中声明事件

为了声明一个新事件,需要两件东西。首先,必须创建一个可以发布的事件值,以便其他斯可以订阅新创建的事件。这一次,我们需要使用 F# 特有的 IEvent <'T> 接口,而不是 .NET 的 IObservable<'T>。我们还需要一种触发该事件的方法。在 C# 中,可以使用方法调用的语法,来触发事件,只是从声明的类中。当我们在 F# 中创建一个新的事件时,就会得到触发它的函数。

所有这一切,用示例来说明,就更清晰了。清单 16.6 显示了一个简单的具体对象类型(类),只公开一个事件和有时触发事件的一个方法。

Listing 16.6 Declaring an event as a class member (F# Interactive)

> type Counter() =
let mutable num = 0
let changedEvt = new Event<_>()

member x.SignChanged = changedEvt.Publish
member x.Add(n) =
let original = num
num <- num + n
if (sign(original) <> sign(num)) then
changedEvt.Trigger(num);;

> let c = Counter()
c.SignChanged |> Observable.add (printfn "Number: %d");;
type Counter = (...)

> c.Add(10);;
Number: 10

> c.Add(10);;
> c.Add(-30);;
Number: –10

Counter 类包含一个存储当前数值的可变字段,Add 方法修改这个字段,当存储数值变化时,应该触发 SignChanged 事件。为了声明一个新的事件,我们使用来自 F# 库的 Event<'T> 类。此类包含 Publish 成员,返回相应的、可以监听的 IEvent<'T> 值,和运行这个事件的 Trigger 成员。

清单 16.6 显示在类型声明中处理事件的典型方式。将Event 类的实例存储为本地值 ,公开由 Publish 成员返回的事件值,作为该类的公共成员,以便用户可以监听这个事件,但不能触发它。当满足适当条件时,使用 Trigger 成员,触发该事件。

声明兼容 C# 的事件

我们在这一节中使用的、创建事件的技术可以很自然地用于 F#,但不能显示为标准的 C# 事件。F# 编译器不会以任何特殊的方式,对待 IEvent<'T> 类型的属性,因此,它将 SignChanged 编译为一个标准属性的成员。我们可以在 C# 中使用接口的 AddHandler 方法的,但这会引起混乱。

幸运的是,F# 编译器提供了一种简单的方法解决此问题。如果要在 F# 中声明一个标准的 .NET 事件,可以使用 CLIEvent 属性值。编译器能够理解这个属性值,在这里,编译器将创建一个事件,可以使用 C# 中的 += 运算符和-= 运算符进行访问:

type Counter() =
[<CLIEvent>]
member x.SignChanged = ev.Publish

到目前为止,F# 我们创建的事件和常用的 C# 事件的另一个区别,是 F# 使用它自己的泛型委托类型(Handler<T>)。如果要使用某些其他委托时,可以用 Event<'TDel, 'T> 类创建事件,它用第一个参数值来指定委托的类型。例如,在典型的 Windows 编程中,可以使用 Event<EventHandler,EventArgs> 类型来创建事件。

到目前为止,我们已经研究了一些把事件作为一等值的好处。最重要的概念可能是使用高阶函数处理事件的能力,视其为范围内序列的值。现在,我们将扩展前一章的动画示例,允许用户和动画进行交互。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics