![](/img/trans.png)
[英]Why does local variable inside foreach loop conflict with variable declared outside the loop?
[英]Variable declared in for-loop is local variable?
我一直在使用C#很长时间但从未意识到以下情况:
public static void Main()
{
for (int i = 0; i < 5; i++)
{
}
int i = 4; //cannot declare as 'i' is declared in child scope
int A = i; //cannot assign as 'i' does not exist in this context
}
那么,为什么我不能在for块之外使用'i'的值,如果它不允许我声明一个带有这个名字的变量?
我认为for循环使用的迭代器变量仅在其范围内有效。
不允许在for循环和for循环外定义具有相同名称的变量的原因是因为外部作用域中的变量在内部作用域中有效。 这意味着如果允许的话,for循环中会有两个'i'变量。
请参阅: MSDN范围
特别:
在local-variable-declaration(第8.5.1节)中声明的局部变量的范围是声明发生的块。
和
在for语句的for-initializer中声明的局部变量的范围(第8.8.3节)是for-initializer,for-condition,for-iterator和for语句的包含语句。
还有: 局部变量声明 (C#规范的第8.5.1节)
特别:
在local-variable-declaration中声明的局部变量的范围是声明发生的块。 在局部变量的local-variable-declarator之前的文本位置引用局部变量是错误的。 在局部变量的范围内,声明另一个具有相同名称的局部变量或常量是编译时错误。
(强调我的。)
这意味着你的for循环中的i
的范围是for循环。 而for循环之外的i
的范围是整个main方法加上 for循环。 这意味着你在循环中有两次出现i
,根据上面的说法是无效的。
你不被允许做int A = i;
是因为int i
仅限于在for
循环中使用。 因此,它不再可以在for
循环之外访问。
正如您所看到的,这两个问题都是范围界定的结果; 第一个问题( int i = 4;
)将导致for
循环范围内的两个i
变量。 而int A = i;
会导致访问超出范围的变量。
你可以做的是声明i
要作为整个方法的范围,然后在方法和for循环范围中使用它。 这样可以避免违反任何规则。
public static void Main()
{
int i;
for (i = 0; i < 5; i++)
{
}
// 'i' is only declared in the method scope now,
// no longer in the child scope -> valid.
i = 4;
// 'i' is declared in the method's scope -> valid.
int A = i;
}
编辑 :
当然可以更改C#编译器以允许此代码非常有效地编译。 毕竟这是有效的:
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}
for (int i = 5; i > 0; i--)
{
Console.WriteLine(i);
}
但是,为了能够编写代码,您的代码可读性和可维护性是否真的有益:
public static void Main()
{
int i = 4;
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}
for (int i = 5; i > 0; i--)
{
Console.WriteLine(i);
}
Console.WriteLine(i);
}
想想这里可能出现的错误,最后i
打印出0或4? 现在这是一个非常小的例子,一个非常容易跟踪和跟踪的例子,但它肯定比用不同的名称声明外部i
更不易于维护和阅读。
注意:
请注意,C#的范围规则与C ++的范围规则不同。 在C ++中,变量仅在声明它们的范围内,直到块的结尾。 这将使您的代码成为C ++中的有效构造。
J.Kommer的答案是正确的:简单地说,它是非法的一个局部变量来在叠具有本地同名的另一个局部变量声明空间的局部变量声明空间中声明。
此处还有一个违反C#的附加规则。 附加规则是, 使用简单名称来引用两个不同的重叠局部变量声明空间内的两个不同实体是非法的。 所以不仅你的例子是非法的,这也是非法的:
class C
{
int x;
void M()
{
int y = x;
if(whatever)
{
int x = 123;
因为现在简单的名称“x”已经在“y”的局部变量声明空间内使用,意味着两个不同的东西 - “this.x”和本地“x”。
有关这些问题的更多分析,请参见http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/ 。
在循环之后有一种在方法中声明和使用i
的方法:
static void Main()
{
for (int i = 0; i < 5; i++)
{
}
{
int i = 4;
int A = i;
}
}
你可以用Java做到这一点(它可能来自C我不确定)。 为了变量名,它当然有点乱。
如果你在 for
循环之前声明了i
,你认为在循环中声明它应该仍然有效吗?
不,因为那时两者的范围会重叠。
至于无法做到int A=i;
那很简单,因为i
只存在于for
循环中,就像它应该做的那样。
除了J.Kommer的回答(+1 btw)。 NET范围的标准中有这个:
block如果在块构造(如If语句)中声明变量,则该变量的作用域仅在块结束之前。 寿命一直持续到程序结束。
过程如果在过程中声明变量,但在任何If语句之外,则作用域将在End Sub或End Function之前。 变量的生命周期是程序结束。
因此,for循环标头中的int i decalared仅在for循环块期间在范围内, 但它的生命周期将持续到Main()
代码完成。
考虑这一点的最简单方法是将I的外部声明移到循环之上。 那应该是显而易见的。
无论哪种方式都是相同的范围,因此无法完成。
此外,C#的规则在严格编程方面很多时候都没有必要,但是要保持代码的清洁和可读性。
例如,他们可以做到这一点,如果你在循环后定义它然后它是好的,但是有人读取你的代码并错过定义行可能认为它与循环的变量有关。
Kommer的答案在技术上是正确的。 让我用生动的盲屏比喻来解释它。
for-block和封闭外部块之间有一个单向盲屏,这样for-block中的代码可以看到外部代码,但外部代码中的代码无法看到内部代码。
由于外部代码无法看到内部,因此无法使用内部声明的任何内容。 但是由于for-block中的代码可以在内部和外部都看到,因此在两个地方声明的变量都不能通过名称明确地使用。
所以要么你没有看到它,要么你是C#!
看看它以同样的方式,如果你可以声明int
在using
块:
using (int i = 0) {
// i is in scope here
}
// here, i is out of scope
但是,由于int
没有实现IDisposable
,因此无法完成。 但是,它可以帮助某人可视化int
变量如何放置在私有范围中。
另一种方式是说,
if (true) {
int i = 0;
// i is in scope here
}
// here, i is out of scope
希望这有助于可视化正在发生的事情。
我非常喜欢这个功能,因为从for
循环内部声明int
可以使代码保持良好和紧密。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.