22

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# での一般的なイベントの使用に関するものではありません。インターフェイスの側面が重要です。

4

2 に答える 2

22

インターフェイスと実装の両方で 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
于 2012-11-14T14:38:35.300 に答える
13

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# コンパイラが次の 2 つの方法でイベントをコンパイルできるためです。

  • add属性を指定すると、イベントは基になるおよびremove操作を含む .NET イベント (C# と互換性あり) にコンパイルされます。

  • 属性を指定しない場合、イベントは(F# コア ライブラリで定義された)get型の値を返す .NET プロパティ ( を使用)としてコンパイルされます。IEvent<'T>

そのため、インターフェイス定義は実装と一致する必要があります (残念ながら、これを自動的に推測するのは非常に難しいため、コンパイラはそれを行いません)。

どのオプションが必要ですか? コードを C# に公開する場合は、必ずCLIEvent. F# からのみ使用している場合は、あまり問題になりません。ただし、関数にイベントを頻繁に渡す場合は、使用を避ける方が効率的です。たとえば、myTyp.OnMyEvent |> Event.map (...)
(最初の表現では、イベントはオブジェクトにラップされIEvent<_>ますが、2 番目のケースでは、プロパティを使用してオブジェクトを取得できます)。

于 2012-11-14T21:39:02.340 に答える