首页 文章

泛型,重载解析和代理(对不起,找不到更好的 Headers )[重复]

提问于
浏览
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中测试)

如果我尝试使用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>)'

如何将第二次重载作为有效候选者?类型推断正确地确定 TSourceint ,因此 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 回答

  • 3

    是不是因为返回类型不是方法签名的一部分?

    在尝试确定 Foo<TSource> 的哪个重载是必需时,编译器会考虑 Identity<T> 方法 . 如果不考虑返回类型,那么 Identity<int> 同样可以转换为 Func<int, int>Func<int, double>Func<int, anything> .

  • 1

    我认为LukeH是正确的 . 但是,要回答你问题的第二点:lambda的委托已经填写了所有类型(例如,如果 TSourceint ,则始终是 Func<int, int> ),这就是为什么在这种情况下没有歧义 . 它不像函数签名,返回类型被忽略 .

相关问题