我有以下代码(生成给定a,b和c的二次函数)
Func<double, double, double, Func<double, double>> funcGenerator = (a, b, c) => f => f * f * a + b * f + c;
到目前为止,很可爱.
但是,如果我尝试声明一个名为a,b,c或f的变量,visual studio弹出一个"A local variable named 'f' could not be declared at this scope because it would give a different meaning to 'f' which is used in a child scope."
基本上,这会失败,我不知道为什么,因为一个子范围甚至没有任何意义.
Func<double, double, double, Func<double, double>> funcGenerator =
(a, b, c) => f => f * f * a + b * f + c;
var f = 3; // Fails
var d = 3; // Fine
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?
Aar*_*ght 12
我认为您误解的是,声明的顺序与C#编译器相关的范围规则无关紧要.
这个:
Func<double, double, double, Func<double, double>> funcGenerator =
(a, b, c) => f => f * f * a + b * f + c;
var f = 3;
var d = 3;
Run Code Online (Sandbox Code Playgroud)
与此完全相同:
var f = 3;
Func<double, double, double, Func<double, double>> funcGenerator =
(a, b, c) => f => f * f * a + b * f + c;
var d = 3;
Run Code Online (Sandbox Code Playgroud)
范围不是对订单敏感的.你有一个名为的局部变量f,并且你试图声明f在lambda中命名的另一个变量.根据C#规范,这是非法的.
具体来说,它会与lambdas进行变量捕获的能力发生冲突.例如,此代码是合法的:
int x = 3;
Func<int> func = () => x + 1;
Run Code Online (Sandbox Code Playgroud)
这是完全合法的,执行func()将返回4.这就是为什么你不能x在lambda中声明另一个变量的原因- 因为lambda实际上需要能够捕获外部x.
只需更改其中一个f变量的名称即可.
它意味着它所说的.您不允许在lambda范围和包含lambda的范围中使用相同的变量名.子范围是lambda的范围.
确切地确定你违反了哪个C#规则可能会非常棘手.作为一项公共服务,我编写了这本方便的指南,解释了一些更容易混淆的范围规则之间的差异:
http://ericlippert.com/tag/simple-names/
(从底部开始;这些是按时间顺序排列的.)
另外,你对"范围"这个概念似乎有点不清楚 - 这并不奇怪,因为在大多数书中,这个词几乎用来表示作者想要的东西.在C#中,我们仔细地将"范围"定义为"程序文本的区域,其中特定实体可以通过其不合格的名称来引用".例如,在
namespace A
{
public class B
{
private int c;
protected int d;
public void E(int f)
{
int g = f;
Func<int, int> h = i => g * i;
}
}
public class K : B { }
}
Run Code Online (Sandbox Code Playgroud)
A的范围无处不在.B和K的范围在A的声明中无处不在.c的范围在B内无处不在.d和E的范围是B,K的范围以及从B或K派生的任何类.范围f和g和h是E的主体.i的范围是lambda的主体.
请注意,范围和可访问性域之间存在差异.B,K和E 随处可访问,但仅限于特定位置的范围.
另请注意,整个块的h范围.在声明之前使用它是不合法的,但它在声明之前就在范围之内. h