ジェネリックスの非常に奇妙なオーバーロード解決の問題に気づきました...
次の方法を検討してください。
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 => x
とIdentity
、コンパイラは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である可能性がありますが、 !ではありません。Identity
int
int
Identity
Func<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"
それで、誰かがここで何が起こっているのか説明できますか?また、ラムダでは機能するのにメソッドグループでは機能しないのはなぜですか?