Vb.net With语句中的表达式在任务中的lambda表达式中变为空

Vb.net With语句中的表达式在任务中的lambda表达式中变为空,vb.net,lambda,task,Vb.net,Lambda,Task,我发现在任务中执行的lambda表达式中引用成员变量会在使用With语句访问时引发NullReferenceException 例如,我希望下面的代码在控制台上打印两行。第一个函数通过obj.SomeString访问SomeString成员,而第二个函数使用With语句并通过.SomeString访问成员。我希望这两个选项是等效的,但是第二个选项抛出了一个异常 Class Foo Public SomeString As String End Class Module Module1

我发现在任务中执行的lambda表达式中引用成员变量会在使用
With
语句访问时引发
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编译器使用
块和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
_
公共共享子主目录()
Dim var1作为新一代Class1
使用{.SomeString=“Hello World”}将foo设置为新foo
var1.objVar=foo
将var2设置为新的GeneratedClass1.GeneratedClass2,并带有{.var2=var1、.theWithVariable=var1.objVar}
Task.Factory.StartNew(新操作(var2.\u Lambda\u\u\u 1的地址))
var2.theWithVariable=无
Console.ReadKey()
端接头
_
生成的好友类Class1
"方法",
_
公共分新()
端接头
_
公共子新建(ByVal其他生成类别1)
如果(不是其他什么都不是)那么
Me.objVar=other.objVar
如果结束
端接头
“田地
作为Foo的公共objVar
'嵌套类型
_
好友类生成类2
"方法",
_
公共分新()
端接头
_
公共子新建(ByVal其他生成类2)
如果(不是其他什么都不是)那么
Me.theWithVariable=other.theWithVariable
如果结束
端接头
_
公共分包商λλλλ1()
Console.WriteLine(((“1:&Me.var2.objVar.SomeString))
Console.WriteLine(((“2:&Me.theWithVariable.SomeString))
端接头
“田地
将变量设置为Foo的公共对象
生成时的公共var2类别1
末级
末级

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

这是因为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
_
公共共享子主目录()
Dim var1作为新一代Class1
使用{.SomeString=“Hello World”}将foo设置为新foo
var1.objVar=foo
将var2设置为新的GeneratedClass1.GeneratedClass2,并带有{.var2=var1、.theWithVariable=var1.objVar}
Task.Factory.StartNew(新操作(var2.\u Lambda\u\u\u 1的地址))
var2.theWithVariable=无
Console.ReadKey()
端接头
_
生成的好友类Class1
"方法",
_
公共分新()
端接头
_
公共子新建(ByVal其他生成类别1)
如果(不是其他什么都不是)那么
Me.objVar=other.objVar
如果结束
端接头
“田地
作为Foo的公共objVar
'嵌套类型
_
好友类生成类2
"方法",
_
公共分新()
端接头
_
公共子新建(ByVal其他生成类2)
如果(不是其他什么都不是)那么
Me.theWithVariable=other.theWithVariable
如果结束
端接头
_
公共分包商λλλλ1()
Console.WriteLine(((“1:&Me.var2.objVar.SomeString))
Console.WriteLine(((“2:&Me.theWithVariable.SomeString))
端接头
“田地
将变量设置为Foo的公共对象
生成时的公共var2类别1
末级
末级
您可以看到编译器创建了一个类,该类包含对
With
变量和lambda表达式方法的引用。一旦
With
变量超出范围,它就会被设置为
Nothing
,因此在任务执行时会使用空引用表达式