Vb.net With语句中的表达式在任务中的lambda表达式中变为空
我发现在任务中执行的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
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
,因此在任务执行时会使用空引用表达式