2012-11-07 39 views
9

Tôi đã kiểm tra vị trí của các khai báo biến trong VB.NET không quan trọng, ngoại trừ phạm vi, (đối với this question) và tôi nghĩ tôi nên kiểm tra xem điều gì sẽ xảy ra khi chúng được "dỡ bỏ" vào một đóng. Tôi đã không đọc spec, nhưng tôi không thể giải thích những kết quả này:Tại sao không phải tất cả các biến này được xử lý theo cùng một cách?

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 

Các kết quả trên:

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

inner4 là thiết lập lại mỗi lần có ý nghĩa, như sẽ tất cả hoặc không có khác innerX, nhưng tại sao chỉ inner2?!

+1

Call Sub() làm gì chính xác? – Ahmad

+1

@ AhmadAl-Mutawa Công bằng đủ câu hỏi. Một phiên bản mở rộng là 'Dim closure = Sub() ... End Sub: closure()' và tôi đã thử nghiệm nó và kết quả là như nhau. –

+2

Tôi nghĩ rằng 'inner3' là cái thú vị hơn là' inner2'. Tôi nghĩ rằng nó phải là 0. –

Trả lời

2

Từ MSDN (tôi nhấn mạnh):

[...] những trình biên dịch cơ bản nào, khi nó đi vào một phạm vi mới có chứa một biến dỡ bỏ, trình biên dịch sẽ kiểm tra xem nếu một thể hiện của việc đóng cửa đã tồn tại; nếu vậy, trình biên dịch sẽ tạo ra một thể hiện mới của việc đóng và thiết lập lại giá trị của biến từ lần đóng trước đó.

Lưu ý rằng trình biên dịch chỉ thực hiện kiểm tra ở trên nếu phát hiện vòng lặp hoặc GoTo trong hàm nơi đóng được tạo.

Link

+0

Như tôi đã nói trong câu trả lời mà phiên bản đơn giản (không đóng) của mã này đến từ, _scope_ là khối nơi khai báo, nhưng _lifetime_ là toàn bộ thường trình. Bạn có bất kỳ tài liệu tham khảo cho những gì đang xảy ra trong việc đóng cửa? –

+0

@MarkHurd - xin lỗi vì đã mơ hồ, đó là một ký ức cũ tôi đã phân tích sai thành câu trả lời. Tôi tìm thấy một tài liệu tham khảo cho bạn. –

+0

+1 cho đến nay, khi bạn đã xác định hai điều: VB đang làm một cái gì đó "đặc biệt" ở đây, và nhìn vào mã này trong Reflector có thể sẽ xác nhận những gì đang xảy ra. –

2

(Đây là thêm một bình luận, nhưng cần quá nhiều mã để giữ nó như một.)

Reflector không hiển thị đang xảy ra:

<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 

(Điều này được dựa trên mã của tôi bao gồm Try bên ngoài số For.)

Bạn có thể thấy ở đây For vòng lặp (xem như một vòng lặp Do với $VB$Local_i thiết lập trước đó) và khu vực nội Do tạo đóng cửa mà không có trường hợp trước đây của việc đóng cửa thông qua tại, nhưng Try không được điều trị mà .

Vẫn không biết tại sao? Trông giống như một lỗi đối với tôi. Nếu tôi không nhận được một "lý do" hợp lý (:-)) trong một ngày hoặc lâu hơn, tôi sẽ đặt nó trên Connect. (Ai đó có thể xác nhận. NET 4.5 VB11 thực hiện giống nhau không?)

+0

Qua LinqPad 5 beta, điều này đã được sửa trong VB.NET 14: Dòng thứ hai bây giờ là '1, 1, 1, 1, 0'. –

+0

chỉ là một ý tưởng !! bởi vì các biến được khai báo bên trong khối try là vô hình bên ngoài khối, và cách hệ thống xử lý các ngoại lệ, làm cho sub cuộc gọi trông giống như nó nằm ngoài khối. do đó biến bên trong2 không phải là trong khối phụ gọi. thử dùng sub call (var) và truyền inner2 làm tham số cho sub call. – milevyo

+0

@milevyo Tôi chắc chắn có nhiều cách giải quyết khác nhau, nhưng phiên bản sau này "sửa lỗi" điều này cho thấy nó nên là theo cách đó. –

Các vấn đề liên quan