重载的方法组参数会混淆重载决策?

时间:2011-03-05 12:25:06

标签: c# c#-4.0 overload-resolution method-group

以下调用重载的Enumerable.Select方法:

var itemOnlyOneTuples = "test".Select<char, Tuple<char>>(Tuple.Create);

因模糊错误而失败(为清晰起见,删除了名称空间):

The call is ambiguous between the following methods or properties: 
'Enumerable.Select<char,Tuple<char>>
           (IEnumerable<char>,Func<char,Tuple<char>>)'
and 
'Enumerable.Select<char,Tuple<char>>
          (IEnumerable<char>, Func<char,int,Tuple<char>>)'

我当然可以理解为什么明确指定类型参数会导致歧义(这两种情况都会适用),但是在这样做之后我没有看到。

我觉得很清楚,目的是调用第一个重载,方法组参数解析为Tuple.Create<char>(char)。第二个重载不应该适用,因为Tuple.Create重载都不能转换为预期的Func<char,int,Tuple<char>>类型。我是猜测编译器被Tuple.Create<char, int>(char, int)混淆了,但是它的返回类型是错误的:它返回一个二元组,因此不能转换为相关的Func类型。

顺便说一下,以下任何一个都让编译器感到高兴:

  1. 为method-group参数指定一个type-argument:Tuple.Create<char>(也许这实际上是一个类型推断问题?)。
  2. 使参数成为lambda表达式而不是方法组:x => Tuple.Create(x)。 (在Select电话中使用类型推断很好。
  3. 不出所料,尝试以这种方式调用Select的其他重载也会失败:

    var itemIndexTwoTuples = "test".Select<char, Tuple<char, int>>(Tuple.Create);
    

    这里的确切问题是什么?

2 个答案:

答案 0 :(得分:20)

答案 1 :(得分:5)

  

我猜测编译器被Tuple.Create<char, int>(char, int)搞糊涂了,但它的返回类型是错误的:它返回一个两元组。

返回类型不是方法签名的一部分,因此在重载解析期间不会考虑它;只有在选择了重载后才会验证。因此,就编译器所知,Tuple.Create<char, int>(char, int)是一个有效的候选者,它既不比Tuple.Create<char>(char)好也不差,所以编译器无法决定。