csa*_*uve 7 vb.net lambda closures
只是想我会分享这个以防万一其他人遇到这个.
我今天做了类似的事情,花了一些时间来弄清楚为什么这会在运行时引起问题.
这段代码:
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
Run Code Online (Sandbox Code Playgroud)
抛出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
Run Code Online (Sandbox Code Playgroud)
请注意
$VB$Closure_ClosureVariable_7A_6.$VB$Local_VB$t_ref$L0 = Nothing
Run Code Online (Sandbox Code Playgroud)
只有"问题"我真的可以问的是; 这是一个错误或一个奇怪的设计决定,由于某种原因,我没有看到.从现在开始,我几乎要避免使用"With".
这种行为是"按设计",并且是由于该With
陈述经常被误解的细节造成的.
该With
语句实际上将表达式作为参数而不是直接引用(即使它是最常见的用例之一).语言规范的第10.3节保证传递给With
块的表达式仅被计算一次,并且可用于执行With
语句.
这是通过使用临时实现的.因此,当.Member
在With
语句中执行expressio 时,您不会访问原始值,而是指向原始值的临时值.它允许其他有趣的场景,如下所示.
Dim o as New Foo
o.bar = "some value"
With o
o = Nothing
Console.WriteLine(.bar) ' Prints "some value"
End With
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为在With
语句中你没有操作,o
而是临时指向原始表达式.这个临时性只能保证在With
声明的整个生命周期内都存在,因此Nothing
最后会出现这种情况.
在您的示例中,闭包正确捕获临时值.因此,当它在With
语句完成后执行时,临时是Nothing
并且代码适当地失败.
归档时间: |
|
查看次数: |
1114 次 |
最近记录: |