之前写程序只是知道,变量在使用前要初始化,但是却没有仔细地去想过究竟是为什么,直到昨天偶然间遇到了下面这样的问题:
那么和下面这段代码相比较:
static void Main(string[] args)
{
int val;
for (int i = 0; i < 10; i++)
{
val = i + i;
}
//{ val = 1; }
// 这里会提示没有赋值的局部变量
//Console.WriteLine(val);
Console.ReadKey();
}
提示:使用了未赋值的局部变量"val"{
int val;
for (int i = 0; i < 10; i++)
{
val = i + i;
}
//{ val = 1; }
// 这里会提示没有赋值的局部变量
//Console.WriteLine(val);
Console.ReadKey();
}
那么和下面这段代码相比较:
static void Main(string[] args)
{
int i;
for (i = 0; i < 10; i++)
{
}
Console.WriteLine(i);
Console.ReadKey();
}
{
int i;
for (i = 0; i < 10; i++)
{
}
Console.WriteLine(i);
Console.ReadKey();
}
同样变量 int i 也是声明于for循环的外部,但是最后却可以通过Console.WriteLine()来输出这个i的值。通过查看反编译的IL代码发现,其实这个变量 i 是在for结构的循环体外部被初始化的,IL代码如下:
.locals init ([0] int32 i,
[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldc.i4.0 // 出栈
IL_0002: stloc.0 // 压栈,将0赋给变量i
// 下面才进入循环体
IL_0003: br.s IL_000b
IL_0005: nop
IL_0006: nop
IL_0007: ldloc.0
IL_0008: ldc.i4.1
IL_0009: add
IL_000a: stloc.0
IL_000b: ldloc.0
IL_000c: ldc.i4.s 10
IL_000e: clt
IL_0010: stloc.1
IL_0011: ldloc.1
IL_0012: brtrue.s IL_0005
// 循环结束
IL_0014: ldloc.0
IL_0015: call void [mscorlib]System.Console::WriteLine(int32)
[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldc.i4.0 // 出栈
IL_0002: stloc.0 // 压栈,将0赋给变量i
// 下面才进入循环体
IL_0003: br.s IL_000b
IL_0005: nop
IL_0006: nop
IL_0007: ldloc.0
IL_0008: ldc.i4.1
IL_0009: add
IL_000a: stloc.0
IL_000b: ldloc.0
IL_000c: ldc.i4.s 10
IL_000e: clt
IL_0010: stloc.1
IL_0011: ldloc.1
IL_0012: brtrue.s IL_0005
// 循环结束
IL_0014: ldloc.0
IL_0015: call void [mscorlib]System.Console::WriteLine(int32)
而上面的例子中,变量 int val 实际上是在for结构的循环体内部初始化的,通过查阅《C#入门经典》找到了答案,下面引用书中的原文:
“实际上任何变量,只声明一个简单的变量类型,并不会引起其他的变化,只有在给变量赋值后,这个值才占用一块内存空间。如果这种占据内存空间的行为在循环中发生,该值实际上被定义为一个局部值,在循环的外部会超出其作用域,从而失去作用。在循环外部赋值可以确保该值是主体代码的局部值,在循环内部它仍处于作用域中。”
比较奇怪的时,在上面第一段代码中,如果注释掉Console.WriteLine(val);这句编译可以通过,并且调试时发现,在for循环结束后仍然可以通过“即时窗口”调到该变量val的值。(如图)
实际上CLR允许任何语法正确的代码,其实这个只是C#编译器的逻辑检查功能罢了,它保证了程序的正确性,它认为FOR可以一次也不循环,也就有可以变量没赋值就使用,这样程序也就有可能会出现程序员不预期的效果,这是编译器的辅助功能,当然也可以通过设置编译器选项,降低编译器的代码安全检查标准来避免这个问题,但是一般来说并不推荐这样做。