With语句中的表达式在Task中的lambda表达式中变为Nothing

时间:2016-09-07 23:37:52

标签: vb.net lambda task

我发现在使用NullReferenceException语句访问它时,在任务中执行的lambda表达式中引用成员变量会引发With

例如,我希望以下代码在控制台上打印两行。第一个通过SomeString访问obj.SomeString成员,而第二个使用With语句并通过.SomeString访问成员。我希望两个选项都是等价的,但第二个选项会引发异常。

Class Foo
    Public SomeString As String
End Class

Module Module1

    Sub Main()

        Dim obj As New Foo With {.SomeString = "Hello World"}

        With obj
            Task.Factory.StartNew(
                Sub()
                    Console.WriteLine("1:" + obj.SomeString) ' works
                    Console.WriteLine("2:" + .SomeString) ' NullReferenceException here
                End Sub)
        End With

        Console.ReadKey()

    End Sub

End Module

当我将Console.ReadKey()语句移到With语句中时,代码可以正常工作。

我通过不使用With语句修复了实际代码,但我仍然不知道我在这里缺少什么概念。为什么我可以访问lambda表达式中的obj变量的成员,而不是With表达式的成员?它没有被垃圾收集,因为在抛出异常时我仍然可以在调试器中看到它。表达式似乎超出了范围(或者类似的东西),但为什么编译器不能按照我的预期执行,并将其视为与obj相同?

1 个答案:

答案 0 :(得分:2)

由于voodoo,VB编译器支持With块和lambda表达式。如果你通过像Redgate的Reflector这样的反编译器查看你的代码,你的代码会转换成类似下面的代码,除了我将变量重命名为VB支持的变量;它们可能很长并且包含对VB变量名无效的字符

<STAThread> _
Public Shared Sub Main()
     Dim var1 As New GeneratedClass1
     Dim foo As New Foo With {.SomeString = "Hello World"}
     var1.objVar = foo

     Dim var2 As New GeneratedClass1.GeneratedClass2 With {.var2 = var1, .theWithVariable = var1.objVar}
     Task.Factory.StartNew(New Action(AddressOf var2._Lambda___1))
     var2.theWithVariable = Nothing
     Console.ReadKey()
End Sub

<CompilerGenerated> _
Friend Class GeneratedClass1
     ' Methods
     <DebuggerNonUserCode> _
     Public Sub New()
     End Sub

     <DebuggerNonUserCode> _
     Public Sub New(ByVal other As GeneratedClass1)
          If (Not other Is Nothing) Then
                Me.objVar = other.objVar
          End If
     End Sub


     ' Fields
     Public objVar As Foo

     ' Nested Types
     <CompilerGenerated> _
     Friend Class GeneratedClass2
          ' Methods
          <DebuggerNonUserCode> _
          Public Sub New()
          End Sub

          <DebuggerNonUserCode> _
          Public Sub New(ByVal other As GeneratedClass2)
                If (Not other Is Nothing) Then
                     Me.theWithVariable = other.theWithVariable
                End If
          End Sub

          <CompilerGenerated> _
          Public Sub _Lambda___1()
                Console.WriteLine(("1:" & Me.var2.objVar.SomeString))
                Console.WriteLine(("2:" & Me.theWithVariable.SomeString))
          End Sub


          ' Fields
          Public theWithVariable As Foo
          Public var2 As GeneratedClass1
     End Class
End Class

您可以看到编译器创建了一个类,该类包含对With变量的引用和lambda表达式的方法。只要With变量超出范围,它就会设置为Nothing,因此当任务执行时,空引用表达式。