[英]How should an event be declared in an F# interface?
The standard way to publish events in F# now seems to be the following: 现在,在F#中发布事件的标准方法如下:
type MyDelegate = delegate of obj * EventArgs -> unit
type MyType () =
let myEvent = new Event<MyDelegate, EventArgs> ()
[<CLIEvent>]
member this.OnMyEvent = myEvent.Publish
and that works fine, including being able to consume that event from other .NET languages (C# at least that I've tested). 并且工作正常,包括能够从其他.NET语言中消耗该事件(C#至少我已经测试过)。 But how can you make that event show up in an interface?
但是如何让这个事件出现在界面中呢? Here's what I'm trying...
这是我正在尝试的......
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
But that won't compile - the member within the interface causes an error: "No abstract or interface member was found that corresponds to this override". 但是这不会编译 - 接口中的成员会导致错误:“找不到与此覆盖相对应的抽象或接口成员”。 How should I be declaring the event in my interface?
我该如何在界面中声明该事件? Or is it that my member syntax is wrong?
或者是我的成员语法错了吗?
Note - this is not about consuming C# events in F# or general event usage in F# - the interface aspect is key. 注意 - 这不是关于消耗F#中的C#事件或F#中的一般事件使用 - 接口方面是关键。
You need to specify the CLIEvent attribute on both the interface and the implementation. 您需要在接口和实现上指定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
In addition to the thr's answer, it is also valid to write code that does not use the CLIEvent
attribute in both the interface and the implementation: 除了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
The reason for this is that the F# compiler can compile events in two ways: 原因是F#编译器可以通过两种方式编译事件:
When you do specify the attribute, the event gets compiled into a .NET event (compatible with C#) with underlying add
and remove
operations. 当您指定属性时,事件将被编译为带有基础
add
和remove
操作的.NET事件(与C#兼容)。
When you don't specify the attribute, the event is compiled as a .NET property (with get
) that returns a value of a type IEvent<'T>
(defined in the F# core library). 如果未指定该属性,则会将事件编译为.NET属性(带有
get
),该属性返回IEvent<'T>
类型的值(在F#核心库中定义)。
So, your interface definition has to match with the implementation (sadly, infering this automatically is quite tricky, so the compiler does not do that). 因此,您的接口定义必须与实现相匹配(遗憾的是,自动推断它非常棘手,因此编译器不这样做)。
Which option do you need? 你需要哪个选项? If you're exposing code to C#, then you definitely need
CLIEvent
. 如果您将代码暴露给C#,那么您肯定需要
CLIEvent
。 If you're using it just from F# then it does not matter too much - however, it might be more efficient to avoid using it when you often pass the event to functions - for example in myTyp.OnMyEvent |> Event.map (...)
如果你只是从F#中使用它,那么它并不重要 - 但是,当你经常将事件传递给函数时,避免使用它可能更有效 - 例如在
myTyp.OnMyEvent |> Event.map (...)
(in the first representation, the event needs to be wrapped into an IEvent<_>
object while in the second case, it can just obtain the object using the property). (在第一种表示中,事件需要包装到
IEvent<_>
对象中,而在第二种情况下,它可以使用属性获取对象)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.