熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

VB.NET循環體內的局部變量

2022-06-13   來源: .NET編程 

  我們知道在類或者結構初始化的時候 成員變量最好不要顯式賦以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#不容許局部變量不顯式初始化就開始使用編譯器會提示錯誤無法編譯


From:http://tw.wingwit.com/Article/program/net/201311/15512.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.