Oha*_*der 11 c# type-inference .net-4.0 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;
}
Run Code Online (Sandbox Code Playgroud)
CS0121错误的描述是
以下方法或属性之间的调用是不明确的:
'System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>, System.Func<string,decimal>)'和'System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>, System.Func<string,decimal?>)'
我不明白的是,什么信息s => GetValue(s)给编译器根本GetValue不-不是前者,后者的语法糖?
Eri*_*ert 18
马克的答案是正确的,但可以使用更多的解释.
问题确实是由于方法组的处理方式和处理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<string,double>(...),但它们是相互关联的唯一方式是lambda表达式包括一个呼叫GetValue().在转换为委托时,方法组与返回类型的lambda表达式具有不同的转换规则.请参阅为什么Func <T>与Func <IEnumerable <T >>不明确?和重载的方法组参数混淆重载决议?.