我们知道,在类或者结构初始化的时候, 成员变量最好不要显式赋以0、Nothing、False等初值,这样不但没有必要而且会降低性能。因为成员变量首先会被分配内存空间,并且该内存空间自动用“0”进行初始化,因此显式的赋值会增加指令操作而影响性能。 但如果是局部变量呢? 一般情况下,如果不显式初始化局部变量,局部变量会被自动也赋以空值、0、或者false。 '例如以下代码 Dim b As Boolean Console.WriteLine(b) Dim rnd1 As Random If rnd1 Is Nothing Then Console.WriteLine("yes") End If '最终会输出:"false yes" 不过对于引用类型的Random,编译器会给出“ 变量“rnd1”在赋值前被使用。可能会在运行时导致 null 引用异常。”的警告。值类型则没有任何警告。 ok,再来看下这段代码: 1Module Module1Module Module1 2 3Sub Main()Sub Main() 4Dim rnd As New Random(1000) 5For i As Integer = 0 To 4 6Dim b As Boolean 7Console.WriteLine(b) 8If rnd.NextDouble > 0.5 Then 9b = True 10End If 11Next 12End Sub 13 14End Module Module Module1 Sub Main() Dim rnd As New Random(1) For i As Integer = 0 To 9 Dim b As Boolean Console.WriteLine(b) If rnd.NextDouble < 0.5 Then b = True End If Next For i As Integer = 0 To 9 Dim rnd1 As Random If rnd1 Is Nothing Then Console.WriteLine("yes") Else Console.WriteLine("no") End If rnd1 = New Random Next End Sub End Module照说每次循环都重新定义并初始化该局部变量,期望的输出值应该一直都是false。 但猜猜实际最终输出结果是什么,false,false,false,true,true!! 就是这个怪诞的行为让我困扰了很久。 ok,我们看看对应的il代码: .method public static void Main() cil managed { .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() .entrypoint .maxstack 2 .locals init ( [0] class [mscorlib]System.Random rnd, [1] bool b, [2] int32 i, [3] bool VBCGt_boolS0, [4] int32 VBCGt_i4S0, [5] int32 num) L_0000: nop L_0001: ldc.i4 0x3e8 L_0006: newobj instance void [mscorlib]System.Random::.ctor(int32) L_000b: stloc.0 L_000c: ldc.i4.0 L_000d: stloc.2 L_000e: ldloc.1 L_000f: call void [mscorlib]System.Console::WriteLine(bool) L_0014: nop L_0015: ldc.i4.1 L_0016: stloc.1 L_0017: nop L_0018: ldloc.2 L_0019: ldc.i4.1 L_001a: add.ovf L_001b: stloc.2 L_001c: ldloc.2 L_001d: ldc.i4.4 L_001e: stloc.s num L_0020: ldloc.s num L_0022: ble.s L_000e L_0024: ldc.i4.0 L_0025: stloc.s VBCGt_i4S0 L_0027: ldloc.3 L_0028: call void [mscorlib]System.Console::WriteLine(bool) L_002d: nop L_002e: ldc.i4.1 L_002f: stloc.3 L_0030: nop L_0031: ldloc.s VBCGt_i4S0 L_0033: ldc.i4.1 L_0034: add.ovf L_0035: stloc.s VBCGt_i4S0 L_0037: ldloc.s VBCGt_i4S0 L_0039: ldc.i4.4 L_003a: stloc.s num L_003c: ldloc.s num L_003e: ble.s L_0027 L_0040: nop L_0041: ret } 晕......编译器居然自动把变量b声明提升到循环体之外......因此就出现了上述的行为。(注:晕啊,以前学c的时候,就学过for(;;){int i=5;}里,i只在第一次声明,以前的基础知识全部忘光光。感谢psic的指正。) 我个人猜测,编译器这样做的原因大概是为了性能。可是这样实在是容易造成奇异的行为,最郁闷的是,值类型的变量,编译器根本连警告都没有。 所以,VB.NET中使用局部变量,尤其在循环体内使用局部变量,一定要进行初始化。 PS:这个话题在c里就没有任何意义了。c不容许局部变量不显式初始化就开始使用,编译器会提示错误无法编译。
鱼台论坛http://bbs.370827.org/thread-5722-1-1.html (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|