方法推理不适用于方法组
考虑
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
不 – 对于前者不是后者的语法糖?
马克的答案是正确的,但可以使用更多的解释。
问题确实是由于方法组的处理方式和lambda的处理方式之间存在细微差别。
具体来说,细微差别在于方法组仅根据参数是否匹配而被认为是可转换为委托类型,而不是基于返回类型是否匹配。 Lambdas检查参数和返回类型。
这种奇怪规则的原因是方法组转换为委托本质上是重载解决问题的解决方案。 假设D是委托类型double D(string s)
,M是包含接受字符串并返回字符串的方法的方法组。 当解决从M到D的转换的含义时,我们执行重载解析,就像你说过M(字符串)一样。 重载决策将选择接受字符串并返回字符串的M,因此M可转换为该委托类型, 即使转换稍后会导致错误 。 如果你说“string s = M(null);”就像“常规”重载决策会成功一样 – 重载解析成功,即使稍后导致转换失败。
这个规则很微妙,有点奇怪。 它的结果是你的方法组可以转换为所有不同的委托类型 ,这是委托代表的每个版本的Sum的第二个参数。 由于无法找到最佳转换,因此方法组Sum
的重载分辨率不明确。
方法组转换规则似乎是合理的,但在C#中有点奇怪。 我有点烦恼,他们与更“直观正确”的lambda转换不一致。
s => GetValue(s)
是一个lambda表达式, GetValue
是一个方法组,这是一个完全不同的东西。 它们都可以被认为是new Func
语法糖,但它们彼此相关的唯一方式是lambda表达式包括对GetValue()
的调用。 在转换为委托时,方法组与返回类型的lambda表达式具有不同的转换规则。 请参阅为什么Func