C# 方法推理不适用于方法组

C# 方法推理不适用于方法组,c#,.net-4.0,type-inference,method-group,C#,.net 4.0,Type Inference,Method Group,考虑 void Main() { var list = new[] {"1", "2", "3"}; list.Sum(GetValue); //error CS0121 list.Sum(s => GetValue(s)); //works ! } double GetValue(string s) { double val; double.TryParse(s, out val); return val; } CS0121错误的描述如

考虑

void Main()
{
    var list = new[] {"1", "2", "3"};
    list.Sum(GetValue); //error CS0121
    list.Sum(s => GetValue(s)); //works !
}

double GetValue(string s)
{
    double val;
    double.TryParse(s, out val);
    return val;
}
CS0121错误的描述如下所示

以下方法或属性之间的调用不明确:
'System.Linq.Enumerable.Sum(System.Collections.Generic.IEnumerable,
System.Func)
'System.Linq.Enumerable.Sum(System.Collections.Generic.IEnumerable,
System.Func
)'


我不明白的是,
s=>GetValue(s)
给编译器的信息是什么,而
GetValue
没有——后者不是前者的语法糖吗?

s=>GetValue(s)
是一个lambda表达式,
GetValue
是一个方法组,这是完全不同的事情。它们都可以被看作是
newfunc(…)
的语法糖,但它们相互关联的唯一方式是lambda表达式包含对
GetValue()
的调用。在转换为委托时,方法组在返回类型方面与lambda表达式有不同的转换规则。请参阅和。

马克的答案是正确的,但需要更多的解释

问题确实是由于处理方法组的方式与处理lambda的方式之间存在细微差异

具体地说,微妙的区别在于,方法组被认为是可转换为委托类型的,这仅仅取决于参数是否匹配,而不是取决于返回类型是否匹配。lambda检查参数和返回类型

这个奇怪规则的原因是方法组到委托的转换本质上是重载解析问题的解决方案。假设D是委托类型
double D(string s)
,M是一个方法组,其中包含一个接受字符串并返回字符串的方法。当解析从M到D的转换的含义时,我们执行重载解析,就好像您说的是M(string)。重载解析将选择接受字符串并返回字符串的M,因此M可以转换为该委托类型,即使转换稍后会导致错误。正如如果您说“string s=M(null);”则“常规”重载解析将成功一样——重载解析将成功,即使这会导致以后的转换失败

这条规则很微妙,有点怪异。这里的结果是,您的方法组可以转换为所有不同的委托类型,这些委托类型是接受委托的每个Sum版本的第二个参数。由于找不到最佳转换,方法组
Sum
上的重载解析不明确


方法组转换规则是合理的,但在C#中有点奇怪。我有点恼火,因为它们与更“直观正确”的lambda转换不一致。

如果你有一台时间机器,你会如何改变它们?你会让他们考虑回归类型,比如兰贝达吗?或者你会做出一个不同的细微变化?很有趣!我在LinqPad中使用了它,事实上,即使我有
双D1(字符串s)
int D1(字符串s)
,一个签名为
字符串M(字符串)
的方法组也会产生一个不明确的调用错误,即使这两个签名无论如何都不适合。这与lambda不同,lambda会尝试所有方法,并在它尝试的最后一个(第一个?)方法上给您一个转换错误。但是,如果没有重载解决问题(并且使用了错误的签名),那么方法组错误(“M具有错误的返回类型”)的信息量比lambda稍微多一些(“无法将类型'string'隐式转换为'double'”)