泛型、重载解析和委托(抱歉,找不到更好的标题)[重复]

问题描述 投票:0回答:2

可能重复:
为什么 Func 与 Func> 不明确?

我注意到泛型有一个非常奇怪的重载解析问题......

考虑以下方法:

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"

但是如果我将

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>)'

第二个重载如何成为有效候选者?类型推断正确地确定

TSource
int
,因此
T
方法的
Identity
参数也必须是
int
,因此返回类型也必须是
int
...
Identity 
可以是
Func<int,int>
Func<double,double>
,但不是
Func<int,double>

而且情况变得更糟!即使我显式指定所有类型参数,我仍然会得到相同的错误:

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

这里怎么会有歧义呢?据我所知,需要

Func<int,double>
的重载不可能成为候选者。我想解释一定在规范中的某个地方,但我找不到相关的位......或者它可能是编译器中的错误,但我想这不太可能。

请注意,如果我显式创建委托,它确实有效:

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

那么,有人可以解释一下这是怎么回事吗?另外,为什么它可以与 lambda 一起使用,但不能与方法组一起使用?

c# generics overload-resolution
2个回答
3
投票

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

编译器在尝试决定需要哪种

Identity<T>
重载时,并未考虑
Foo<TSource>
方法的参数类型和返回类型保证相同的事实。如果不考虑返回类型,则
Identity<int>
同样可以转换为
Func<int, int>
Func<int, double>
Func<int, anything>


1
投票

我认为LukeH是正确的。然而,要回答你问题的第二点:lambda 的委托已经填写了所有类型(例如,如果

Func<int, int>
TSource
,则始终是
int
),这就是为什么在那种情况。它不像函数签名那样忽略返回类型。

© www.soinside.com 2019 - 2024. All rights reserved.