如何在F#界面中声明事件?

时间:2012-11-14 14:16:37

标签: events interface f#

现在,在F#中发布事件的标准方法如下:

type MyDelegate = delegate of obj * EventArgs -> unit

type MyType () =
    let myEvent = new Event<MyDelegate, EventArgs> ()

    [<CLIEvent>]
    member this.OnMyEvent = myEvent.Publish

并且工作正常,包括能够从其他.NET语言中使用该事件(C#至少是我测试过的)。但是如何让这个事件出现在界面中呢?这就是我正在尝试的......

type MyDelegate = delegate of obj * EventArgs -> unit

type IMyType =
    abstract member OnMyEvent : IEvent<MyDelegate, EventArgs>

type MyType () =
    let myEvent = new Event<MyDelegate, EventArgs> ()

    interface IMyType with
        [<CLIEvent>]
        member this.OnMyEvent = myEvent.Publish

但是这不会编译 - 接口中的成员会导致错误:“找不到与此覆盖相对应的抽象或接口成员”。我该如何在界面中声明该事件?或者是我的成员语法错了吗?

注意 - 这是关于在F#中使用C#事件或在F#中使用常规事件 - 接口方面是关键。

2 个答案:

答案 0 :(得分:21)

您需要在接口和实现上指定CLIEvent属性。

open System;

type MyDelegate = delegate of obj * EventArgs -> unit

type IMyType =
    [<CLIEvent>]
    abstract member OnMyEvent : IEvent<MyDelegate, EventArgs>

type MyType () =
    let myEvent = new Event<MyDelegate, EventArgs> ()

    interface IMyType with
        [<CLIEvent>]
        member this.OnMyEvent = myEvent.Publish

答案 1 :(得分:12)

除了thr的答案之外,编写在接口和实现中不使用 CLIEvent属性的代码也是有效的:

type MyDelegate = delegate of obj * EventArgs -> unit

type IMyType =
    abstract member OnMyEvent : IEvent<MyDelegate, EventArgs>

type MyType () =
    let myEvent = new Event<MyDelegate, EventArgs> ()    
    interface IMyType with
        member this.OnMyEvent = myEvent.Publish

原因是F#编译器可以通过两种方式编译事件:

  • 当您指定属性时,事件将被编译为带有基础addremove操作的.NET事件(与C#兼容)。

  • 如果未指定属性,则事件将编译为.NET属性(带get),该属性返回类型IEvent<'T>的值(在F#核心中定义)库)。

所以,你的接口定义必须与实现相匹配(遗​​憾的是,自动推断它非常棘手,因此编译器不这样做。)

您需要哪个选项?如果您将代码暴露给C#,那么您肯定需要CLIEvent。如果你只是从F#中使用它,那么它并不重要 - 但是,当你经常将事件传递给函数时,避免使用它可能更有效 - 例如在myTyp.OnMyEvent |> Event.map (...)中 (在第一个表示中,事件需要包装到IEvent<_>对象中,而在第二种情况下,它可以使用属性获取对象。)