我发现在使用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
相同?
答案 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
,因此当任务执行时,空引用表达式。