【问题标题】:Expression in With statement becomes Nothing in lambda expression in TaskWith 语句中的表达式在 Task 中的 lambda 表达式中变为 Nothing
【发布时间】:2016-09-07 23:37:52
【问题描述】:

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

例如,我希望以下代码在控制台上打印两行。第一个通过obj.SomeString 访问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 一样?

【问题讨论】:

    标签: vb.net lambda task


    【解决方案1】:

    这是因为 VB 编译器支持 With 块和 lambda 表达式的巫术。如果你通过像 Redgate's 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,因此在任务执行时为空引用表达式。

    【讨论】:

      猜你喜欢
      • 2011-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-19
      • 2016-12-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多