只是想我会分享这个以防其他人遇到这个问题。
我今天做了类似的事情,我花了一段时间才弄清楚为什么这会在运行时导致问题。
这段代码:
Public Class foo
Public bar As String = "blah"
End Class
Public Sub DoInline()
Dim o As New foo
Dim f As Func(Of String)
With o
f = Function() .bar
End With
Try
Console.WriteLine(f.DynamicInvoke())
Catch ex As Reflection.TargetInvocationException
Console.WriteLine(ex.InnerException.ToString)
End Try
End Sub
抛出 NullReferenceException。似乎 With 正在使用闭包作为其临时存储,并且在“End With”处,它将闭包的变量设置为 Nothing。
以下是 RedGate Reflector 中的代码:
Public Shared Sub DoInline()
Dim o As New foo
Dim $VB$Closure_ClosureVariable_7A_6 As New _Closure$__1
$VB$Closure_ClosureVariable_7A_6.$VB$Local_VB$t_ref$L0 = o
Dim f As Func(Of String) = New Func(Of String)(AddressOf $VB$Closure_ClosureVariable_7A_6._Lambda$__1)
$VB$Closure_ClosureVariable_7A_6.$VB$Local_VB$t_ref$L0 = Nothing
Try
Console.WriteLine(RuntimeHelpers.GetObjectValue(f.DynamicInvoke(New Object(0 - 1) {})))
Catch exception1 As TargetInvocationException
ProjectData.SetProjectError(exception1)
Console.WriteLine(exception1.InnerException.ToString)
ProjectData.ClearProjectError
End Try
End Sub
注意
$VB$Closure_ClosureVariable_7A_6.$VB$Local_VB$t_ref$L0 = Nothing
我真正能问的唯一“问题”是;这是一个错误还是一个奇怪的设计决策,由于某种原因我没有看到。
从现在开始我几乎会避免使用“With”。
此行为是“设计使然”,是由于经常被误解的细节造成的With
陈述。
The With
语句实际上将表达式作为参数而不是直接引用(即使它是最常见的用例之一)。语言规范第 10.3 节保证表达式传递到With
块仅被评估一次并且可用于执行With
陈述。
这是通过使用临时来实现的。所以当执行一个.Member
a 内的表达式With
声明您访问的不是原始值,而是指向原始值的临时值。它允许其他有趣的场景,如下所示。
Dim o as New Foo
o.bar = "some value"
With o
o = Nothing
Console.WriteLine(.bar) ' Prints "some value"
End With
这是有效的,因为在内部With
您没有进行操作的语句o
而是临时指向原始表达式。这个临时对象只能保证在该对象的生命周期内一直存在With
声明,因此是Nothing
d 最后出来。
在您的示例中,闭包正确捕获了临时值。因此,当它在之后执行时With
语句完成临时是Nothing
并且代码正确地失败了。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)