可能重复:为什么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中测试)
如果我尝试使用lambda表达式作为选择器调用 Foo
,一切正常:
Foo(42, x => x); // prints "int"
但是如果我用 Identity
替换 x => x
,则编译器无法在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>)'
如何将第二次重载作为有效候选者?类型推断正确地确定 TSource
是 int
,因此 Identity
方法的 T
参数也必须是 int
,因此返回类型也必须是 int
... Identity
可以是 Func<int,int>
或 Func<double,double>
,但不是 Func<int,double>
!
它变得更糟!即使我明确指定所有类型参数,我仍然会得到相同的错误:
Foo<int>(42, Identity<int>); // The call is ambiguous...
这里怎么会有歧义?据我所知, Func<int,double>
的重载无法成为候选者 . 我想解释必须在规范中的某处,但我不太可能't find the relevant bit... or it might be a bug in the compiler, but I guess it' .
请注意,如果我明确创建委托,它确实有效:
Foo(42, new Func<int, int>(Identity)); // prints "int"
那么,有人可以解释这里发生了什么吗?另外,为什么它适用于lambda但不适用于方法组?
2 回答
是不是因为返回类型不是方法签名的一部分?
在尝试确定
Foo<TSource>
的哪个重载是必需时,编译器会考虑Identity<T>
方法 . 如果不考虑返回类型,那么Identity<int>
同样可以转换为Func<int, int>
,Func<int, double>
或Func<int, anything>
.我认为LukeH是正确的 . 但是,要回答你问题的第二点:lambda的委托已经填写了所有类型(例如,如果
TSource
是int
,则始终是Func<int, int>
),这就是为什么在这种情况下没有歧义 . 它不像函数签名,返回类型被忽略 .