Why don't all of these variables get treated t

2020-06-14 00:28发布

问题:

I was checking that the position of variable declarations in VB.NET don't matter, except for scope, (for this question) and I thought I better check what happens when they're "lifted" into a closure. I haven't read the spec, but I can't explain these results:

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

The above outputs:

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

inner4 being reset each time makes sense, as would all or none of the other innerX, but why only inner2?!

回答1:

From MSDN (emphasis mine) :

[...]what the compiler basically does, when it enters a new scope containing a lifted variable, the compiler will check to see if an instance of closure already exists; if so, the compiler will create a new instance of closure and reset the value of the variable from the previous closure.

Note that the compiler only does the above check if it detects a loop or a GoTo in the function where the closure is generated.

Link



回答2:

(This is more a comment, but in need of too much code to keep it as one.)

Reflector does show what is happening:

<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

(This is based upon my code which includes a Try outside the For.)

You can see here the For loop (seen as a Do loop with the $VB$Local_i set before) and the inner Do generate closures that do have the previous instance of the closure passed in, but the Try does not get that treatment.

Still don't know why? Looks like a bug to me. If I don't get a reasonable "excuse" (:-)) in a day or so I'll put it on Connect. (Can someone confirm .NET 4.5 VB11 performs the same?)