4

次のフラグメントがあるとします。

type Foo() =
    static member Test (act : unit -> unit) = act()
    static member Test (act : Action) = Foo.Test act.Invoke

最後の行に次のようなエラーが表示されます。このプログラムポイントより前のタイプ情報に基づいて、メソッド'Test'の一意のオーバーロードを判別できませんでした。タイプ注釈が必要になる場合があります。

残念ながら、型アノテーション(act.Invoke : unit -> unit)はあいまいさを解決せず、それを修正するアノテーションを見つけることができません。Actionのバージョンをバージョンのラッパーにしたいと思い->ます。私の特定のユースケースは、F#とC#の両方から呼び出されるクラスを定義することなので、両方の言語からネイティブに機能させたいと考えています。

4

2 に答える 2

4

F#は変換をに挿入するActionので、(理論的には)1つの方法でうまくいくことができます。

type Foo() =
    static member Test (act : Action) = act.Invoke()

Foo.Test (fun () -> ())

Actionコンパイラにとを選択させる方法がわかりませんunit -> unit。他の2つのオプション:

  1. Actionオーバーロードをプライマリにして、Foo.Test(Action(act))
  2. パブリックメソッドから呼び出される3番目の関数にロジックを配置します

しかし、私の推奨は、をとる単一の方法Actionです。変換は自動で行われるため、ある意味で相互運用は無料です。

于 2012-04-17T20:47:11.993 に答える
1

Danielが言うように、デリゲートを受け取るメソッドがF#関数値に適用されると、F#はデリゲートコンストラクターを自動的に挿入するため、おそらく最初のオーバーロードをスキップできます(仕様のセクション8.13.6を参照)。

例と同じ表面積を持つ型を本当に定義したい場合は、let-bound関数に型指定変換が含まれていないという事実を利用できます(メソッド呼び出しのみが含まれます)。

type Foo() = 
    static let test act : unit = act()
    static member Test act = test act
    static member Test (act : System.Action) = test act.Invoke

ただし、これを行うことはあまり役に立ちません。2番目のオーバーロードを定義しようとしたときに遭遇したのと同じように、クラスの外部から最初のオーバーロードを呼び出そうとすると同じ問題が発生するからです。

于 2012-04-18T02:21:40.853 に答える