我们知道在类或者结构初始化的时候 成员变量最好不要显式赋以NothingFalse等初值这样不但没有必要而且会降低性能因为成员变量首先会被分配内存空间并且该内存空间自动用进行初始化因此显式的赋值会增加指令操作而影响性能
但如果是局部变量呢?
一般情况下如果不显式初始化局部变量局部变量会被自动也赋以空值或者false
例如以下代码
Dim b As Boolean
ConsoleWriteLine(b)
Dim rnd As Random
If rnd Is Nothing Then
ConsoleWriteLine(yes)
End If
最终会输出false yes
不过对于引用类型的Random编译器会给出 变量rnd在赋值前被使用可能会在运行时导致 null 引用异常 的警告值类型则没有任何警告
ok再来看下这段代码
Module ModuleModule Module
Sub Main()Sub Main()
Dim rnd As New Random()
For i As Integer = To
Dim b As Boolean
ConsoleWriteLine(b)
If rndNextDouble > Then
b = True
End If
Next
End Sub
End Module
Module Module
Sub Main()
Dim rnd As New Random()
For i As Integer = To
Dim b As Boolean
ConsoleWriteLine(b)
If rndNextDouble < Then
b = True
End If
Next
For i As Integer = To
Dim rnd As Random
If rnd Is Nothing Then
ConsoleWriteLine(yes)
Else
ConsoleWriteLine(no)
End If
rnd = New Random
Next
End Sub
End Module
照说每次循环都重新定义并初始化该局部变量期望的输出值应该一直都是false
但猜猜实际最终输出结果是什么falsefalsefalsetruetrue!!
就是这个怪诞的行为让我困扰了很久
ok我们看看对应的il代码
method public static void Main() cil managed
{
custom instance void [mscorlib]SystemSTAThreadAttribute::ctor()
entrypoint
maxstack
locals init (
[] class [mscorlib]SystemRandom rnd
[] bool b
[] int i
[] bool VB$CG$t_bool$S
[] int VB$CG$t_i$S
[] int num)
L_: nop
L_: ldci xe
L_: newobj instance void [mscorlib]SystemRandom::ctor(int)
L_b: stloc
L_c: ldci
L_d: stloc
L_e: ldloc
L_f: call void [mscorlib]SystemConsole::WriteLine(bool)
L_: nop
L_: ldci
L_: stloc
L_: nop
L_: ldloc
L_: ldci
L_a: addovf
L_b: stloc
L_c: ldloc
L_d: ldci
L_e: stlocs num
L_: ldlocs num
L_: bles L_e
L_: ldci
L_: stlocs VB$CG$t_i$S
L_: ldloc
L_: call void [mscorlib]SystemConsole::WriteLine(bool)
L_d: nop
L_e: ldci
L_f: stloc
L_: nop
L_: ldlocs VB$CG$t_i$S
L_: ldci
L_: addovf
L_: stlocs VB$CG$t_i$S
L_: ldlocs VB$CG$t_i$S
L_: ldci
L_a: stlocs num
L_c: ldlocs num
L_e: bles L_
L_: nop
L_: ret
}
晕编译器居然自动把变量b声明提升到循环体之外因此就出现了上述的行为(注晕啊以前学c的时候就学过for(;;){int i=;}里i只在第一次声明以前的基础知识全部忘光光感谢psic的指正)
我个人猜测编译器这样做的原因大概是为了性能可是这样实在是容易造成奇异的行为最郁闷的是值类型的变量编译器根本连警告都没有
所以VBNET中使用局部变量尤其在循环体内使用局部变量一定要进行初始化
PS这个话题在c#里就没有任何意义了c#不容许局部变量不显式初始化就开始使用编译器会提示错误无法编译