2012-11-07 31 views
9

我在檢查VB.NET中變量聲明的位置並不重要,除了範圍(對於this question),我想我最好檢查一下當它們被「解除」到閉包時會發生什麼。我沒有看過的規範,但我無法解釋這些結果:爲什麼不是所有這些變量都得到相同的處理?

Dim outer As Integer 
For i = 1 To 2 
Dim inner As Integer 
Try 
    Dim inner2 As Integer 
    Do 
    Dim inner3 As Integer 
    Call Sub() 
    Dim inner4 As Integer 
    Console.WriteLine(outer & ", " & inner & ", " & inner2 & ", " & inner3 & ", " & inner4) 
    outer = i 
    inner = i 
    inner2 = i 
    inner3 = i 
    inner4 = i 
    End Sub() 
    Loop Until True 
Finally 
End Try 
Next 

以上輸出:

0, 0, 0, 0, 0 
1, 1, 0, 1, 0 

inner4重置每次有道理的,因爲會全或無的其他innerX,但爲什麼只有inner2?!

+1

Call Sub()是做什麼的? – Ahmad

+1

@ AhmadAl-Mutawa足夠的問題。擴展版本是'Dim closure = Sub()... End Sub:closure()'並且我測試了它,結果是一樣的。 –

+2

我認爲'inner3'是有趣的而不是'inner2'。我認爲應該是0. –

回答

2

從MSDN(重點煤礦):

[...]什麼編譯器基本上沒有,當它進入包含舉起變量一個新的作用域,編譯器會檢查是否關閉的實例已經存在;如果是這樣,編譯器將創建一個新的閉包實例,並重置前一個閉包變量的值。

注意,編譯器只做上述檢查如果它檢測到一個循環或在產生閉合的功能的轉到。

Link

+0

正如我在答案的簡單(非閉包)版本的答案中所說的那樣,_scope_是聲明所在的塊,但_lifetime_是整個例程。你有沒有關於封閉中發生的事情的任何參考? –

+0

@MarkHurd - 抱歉,因爲模糊,這是一個我很難解析成答案的舊內存。我找到了你的參考。 –

+0

+1,因爲你已經確定了兩件事情:VB在這裏做一些「特殊」的事情,並且在Reflector中查看這段代碼可能會確認發生了什麼。 –

2

(這更是一個評論,但需要太多的代碼,以保持其作爲一個。)

反射器是不顯示什麼正在發生的事情:

<STAThread> _ 
Public Shared Sub Main() 
Dim e$__ As New _Closure$__1 
Try 
    Dim e$__2 As New _Closure$__2 
    Dim e$__3 As New _Closure$__3 
    e$__3.$VB$Local_i = 1 
    Do 
     Dim e$__4 As _Closure$__4 
     e$__4 = New _Closure$__4(e$__4) 
     Try 
      Dim e$__5 As New _Closure$__5 
      Do 
       Dim e$__6 As _Closure$__6 
       e$__6 = New _Closure$__6(e$__6) 
       e$__6.$VB$NonLocal_$VB$Closure_ClosureVariable_8_5 = e$__5 
       e$__6.$VB$NonLocal_$VB$Closure_ClosureVariable_6_4 = e$__4 
       e$__6.$VB$NonLocal_$VB$Closure_ClosureVariable_6_6 = e$__3 
       e$__6.$VB$NonLocal_$VB$Closure_ClosureVariable_4_4 = e$__2 
       e$__6.$VB$NonLocal_$VB$Closure_ClosureVariable_2_B = e$__ 
       Dim e_ As VB$AnonymousDelegate_0 = New VB$AnonymousDelegate_0(AddressOf e$__6._Lambda$__1) 
       e_.Invoke 
      Loop While (0 <> 0) 
     End Try 
     e$__3.$VB$Local_i += 1 
    Loop While (e$__3.$VB$Local_i <= 2) 
End Try 
End Sub 

(這是基於我的代碼,其中包括Try以外的For。)

你可以在這裏看到For環路(視爲一個Do循環與之前設置$VB$Local_i)和內Do產生確實有過在封閉的前一個實例關閉,但Try沒有拿到治療。

還不知道爲什麼?對我來說看起來像一個bug。如果我在一天左右沒有得到合理的「藉口」(:-)),我會把它放在Connect上。 (有人可以確認.NET 4.5 VB11執行相同的操作嗎?)

+0

通過LinqPad 5測試版,這已經在VB.NET 14中修復:第二行現在是'1,1,1,1,0'。 –

+0

只是一個想法!因爲在try塊內聲明的變量在其外面是不可見的,而系統處理異常的方式使call子看起來像在塊之外。因此變量inner2不在調用子塊中。嘗試使用call sub(var)並將inner2作爲call sub的參數。 – milevyo

+0

@milevyo我確定有解決方法,但後來的版本「修復」這表明它應該一直這樣。 –

相關問題