考虑
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错误的描述是
The call is ambiguous between the following methods or properties:
'System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>, System.Func<string,decimal>)'
and'System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>, System.Func<string,decimal?>
)'
我不明白的是,s => GetValue(s)
是什么信息?给编译器简单的 GetValue
不是 - 后者不是前者的语法糖吗?
最佳答案
Mark 的回答是正确的,但需要更多解释。
问题确实是由于方法组的处理方式与 lambda 的处理方式之间存在细微差别。
具体来说,细微差别在于方法组被认为可转换为委托(delegate)类型仅基于参数是否匹配,而不是基于是否匹配返回类型匹配。Lambda 会同时检查参数和返回类型。
这个奇怪规则的原因是方法组转换为委托(delegate)本质上是重载决议问题的解决方案。假设 D 是委托(delegate)类型 double D(string s)
,M 是一个方法组,其中包含一个接受字符串并返回字符串的方法。在解析从 M 到 D 的转换的含义时,我们会像您说的是 M(string) 一样进行重载解析。重载解析会选择接受一个字符串并返回一个字符串的 M,因此 M 可以转换为该委托(delegate)类型即使转换稍后会导致错误。正如如果您说“string s = M(null);”,“常规”重载解析会成功一样。 -- 重载解析成功,即使稍后导致转换失败。
这个规则很微妙而且有点奇怪。它的结果是您的方法组可以转换为所有不同的委托(delegate)类型,它们是每个采用委托(delegate)的 Sum 版本的第二个参数。由于找不到最佳转换,方法组 Sum
的重载决策是不明确的。
方法组转换规则看似合理,但在 C# 中有点奇怪。我有点恼火,因为它们与更“直观正确”的 lambda 转换不一致。
关于c# - 方法推断不适用于方法组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24677748/