web-dev-qa-db-ja.com

この「コールがあいまいです」エラーを説明するにはどうすればよいですか?

問題

_T1_から_T2_への単純なマップに加え、_Task<T>_を滑らかにマップするためのオーバーロードである、これら2つの拡張メソッドについて考えてみましょう。

_public static class Ext {
    public static T2 Map<T1, T2>(this T1 x, Func<T1, T2> f)
       => f(x);
    public static async Task<T2> Map<T1, T2>(this Task<T1> x, Func<T1, T2> f)
        => (await x).Map(f);
}
_

ここで、参照型へのマッピングで2番目のオーバーロードを使用すると...

_var a = Task
    .FromResult("foo")
    .Map(x => $"hello {x}"); // ERROR

var b = Task
    .FromResult(1)
    .Map(x => x.ToString()); // ERROR
_

...次のエラーが表示されます:

CS0121:次のメソッドまたはプロパティ間での呼び出しがあいまいです: 'Ext.Map(T1、Func)'と 'Ext.Map(Task、Func)'

値型へのマッピングは正常に機能します。

_var c = Task
    .FromResult(1)
    .Map(x => x + 1); // works

var d = Task
    .FromResult("foo")
    .Map(x => x.Length); // works
_

ただし、マッピングが実際に入力を使用して出力を生成する場合に限ります。

_var e = Task
    .FromResult(1)
    .Map(_ => 0); // ERROR
_

質問

誰かが私にここで何が起こっているのか説明してくれませんか?私はすでにこのエラーの実行可能な修正を見つけることをあきらめましたが、少なくともこの混乱の根本的な原因を理解したいと思います。

その他の注意事項

これまでのところ、残念ながら 私の使用例 では受け入れられない3つの回避策を見つけました。 1つ目は、Task<T1>.Map<T1,T2>()の型引数を明示的に指定することです。

_var f = Task
    .FromResult("foo")
    .Map<string, string>(x => $"hello {x}"); // works

var g = Task
    .FromResult(1)
    .Map<int, int>(_ => 0); // works
_

別の回避策はラムダを使用しないことです:

_string foo(string x) => $"hello {x}";
var h = Task
    .FromResult("foo")
    .Map(foo); // works
_

3番目のオプションは、マッピングを内部関数に制限することです(つまり、_Func<T, T>_)。

_public static class Ext2 {
    public static T Map2<T>(this T x, Func<T, T> f)
        => f(x);
    public static async Task<T> Map2<T>(this Task<T> x, Func<T, T> f)
        => (await x).Map2(f);
}
_

I 。NET Fiddleを作成 上記の例をすべて自分で試すことができます。

ブレースを追加する

var result = (await Task
            .FromResult<string?>("test"))
            .Map(x => $"result: {x}");

あなたのFilterExt非同期メソッドは(xを待つ)に中括弧を追加し、それから非非同期メソッドを呼び出すだけなので、非同期メソッドは何のために必要ですか?

PDATE:多くの.netライブラリで気付いたように、開発者は非同期メソッドに非同期サフィックスを追加するだけです。メソッドにMapAsync、FilterAsyncという名前を付けることができます