kol*_*tiv 18 events f# interface
现在,在F#中发布事件的标准方法如下:
type MyDelegate = delegate of obj * EventArgs -> unit
type MyType () =
let myEvent = new Event<MyDelegate, EventArgs> ()
[<CLIEvent>]
member this.OnMyEvent = myEvent.Publish
Run Code Online (Sandbox Code Playgroud)
并且工作正常,包括能够从其他.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
Run Code Online (Sandbox Code Playgroud)
但是这不会编译 - 接口中的成员会导致错误:"找不到与此覆盖相对应的抽象或接口成员".我该如何在界面中声明该事件?或者是我的成员语法错了吗?
注意 - 这不是关于消耗F#中的C#事件或F#中的一般事件使用 - 接口方面是关键.
thr*_*thr 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
Run Code Online (Sandbox Code Playgroud)
Tom*_*cek 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
Run Code Online (Sandbox Code Playgroud)
原因是F#编译器可以通过两种方式编译事件:
当您指定属性时,事件将被编译为具有底层add
和remove
操作的.NET事件(与C#兼容).
如果未指定该属性,则会将事件编译为.NET属性(with get
),该属性返回类型的值IEvent<'T>
(在F#核心库中定义).
因此,您的接口定义必须与实现相匹配(遗憾的是,自动推断它非常棘手,因此编译器不这样做).
你需要哪个选项?如果您将代码暴露给C#,那么您肯定需要CLIEvent
.如果你只是从F#中使用它那么它并不重要 - 但是,当你经常将事件传递给函数时避免使用它可能更有效 - 例如在myTyp.OnMyEvent |> Event.map (...)
(在第一个表示中,事件需要被包装成一个IEvent<_>
对象,而在第二种情况下,它可以使用属性获取对象).