6

重複の可能性:
Func<T>がFunc<IEnumerable <T >>とあいまいなのはなぜですか?

ジェネリックスの非常に奇妙なオーバーロード解決の問題に気づきました...

次の方法を検討してください。

static void Foo<TSource>(TSource element, Func<TSource, int> selector)
{
    "int".Dump();
}

static void Foo<TSource>(TSource element, Func<TSource, double> selector)
{
    "double".Dump();
}

static T Identity<T>(T value)
{
    return value;
}

(C#4、LINQPadでテスト済み)

セレクターとしてラムダ式を使用して呼び出そうとするとFoo、すべてが正常に機能します。

Foo(42, x => x); // prints "int"

しかし、に置き換えるx => xIdentity、コンパイラは2つのFooオーバーロードのどちらかを決定できません。

Foo(42, Identity);
// The call is ambiguous between the following methods or properties:
// 'UserQuery.Foo<int>(int, System.Func<int,int>)' and
// 'UserQuery.Foo<int>(int, System.Func<int,double>)'

2番目のオーバーロードを有効な候補にするにはどうすればよいですか?TSource型推論はそれを正しく判断するintので、メソッドのTパラメーターも同様である必要があります。したがって、戻り型もそうである必要があります...はaまたはaである可能性がありますが、 !ではありません。IdentityintintIdentityFunc<int,int>Func<double,double>Func<int,double>

そしてそれはさらに悪化します!すべての型パラメーターを明示的に指定しても、同じエラーが発生します。

Foo<int>(42, Identity<int>); // The call is ambiguous...

ここにどのようにあいまいさがありますか?私が知る限り、aをとる過負荷がFunc<int,double>候補になる方法はありません。説明は仕様のどこかにあるはずですが、関連するビットが見つかりません...またはコンパイラのバグかもしれませんが、それはありそうもないと思います。

デリゲートを明示的に作成した場合は機能することに注意してください。

Foo(42, new Func<int, int>(Identity)); // prints "int"

それで、誰かがここで何が起こっているのか説明できますか?また、ラムダでは機能するのにメソッドグループでは機能しないのはなぜですか?

4

2 に答える 2

3

戻り値の型がメソッドのシグネチャの一部ではないという理由だけではありませんか?

メソッドの引数の型と戻り値の型が同じであることが保証されているという事実は、Identity<T>どのオーバーロードが必要かを決定しようとするときに、コンパイラによって考慮されませんFoo<TSource>。戻り値の型が考慮されていない場合は、 、またはIdentity<int>に等しく変換できます。Func<int, int>Func<int, double>Func<int, anything>

于 2011-01-05T00:18:28.960 に答える
1

LukeHが正しいと思います。ただし、質問の2番目のビットに答えるには、ラムダのデリゲートにはすでにすべてのタイプが入力されています(たとえば、常に a Func<int, int>if TSourceis an int)。そのため、その場合にはあいまいさがありません。戻り値の型が無視される関数シグネチャとは異なります。

于 2011-01-05T00:42:28.843 に答える