我在理解以下代码为什么会出现错误的原因时遇到了一些麻烦:
var funs = Enumerable.Range(0, 10).Select(x => (int y) => x + y);
foreach (var fun in funs)
Console.WriteLine("{0}", fun(10));
错误是“无法使用'System.Collections.Generic.IEnumerator.Current'”初始化隐式类型的局部变量声明。我知道如何修复它(通过指定要选择的类型,例如Select<int, Func<int, int>>
或使用辅助方法,例如private static Func<T1, TR> MakeFunc<T1, TR>(Func<T1, TR> f) { return f; }
和使用Select(x => MakeFunc(y => x + y))
。
但是,我想了解编译器无法推断出类型的原因。到目前为止,我最好的猜测是,根据7.15.6,它无法弄清楚它是否应该将内部lambda转换为Func或Expr。我是正确还是还有其他更多内容?
供参考,这是7.15.6所说的内容:
“必须始终将匿名函数F转换为委托类型D或表达式树类型E,直接或通过执行委托创建表达式new D(F)。此转换确定匿名函数的结果。“
答案 0 :(得分:2)
原因很简单:
编译如何得出结论:它应该是Func<int, int>
?他简单不了!
假设您有自己的委托:
public delegate int F(int i);
编译器如何在Func<int, int>
和F
之间进行选择?这些是完全不同的类型,有两个共同点:两个委托都有相同的签名(一个参数和返回类型,都是类型int
)。
所以编译器无法选择;你将不得不这样做:
var funs = Enumerable.Range(0, 10).Select<int, Func<int,int>>(x => y => x + y);
或
var funs = Enumerable.Range(0, 10).Select<int, F>(x => y => x + y);
一个小优点:您可以将int
放在y
之前。