.net 使用在“中指定的实例的成员”;加上;块抛出System.NullReferenceException
我注意到.NET中有一个非常奇怪的行为,我花了一点时间才弄清楚到底发生了什么,因为对我来说,这不是直觉。假设我有以下类别:.net 使用在“中指定的实例的成员”;加上;块抛出System.NullReferenceException,.net,vb.net,visual-studio,.net,Vb.net,Visual Studio,我注意到.NET中有一个非常奇怪的行为,我花了一点时间才弄清楚到底发生了什么,因为对我来说,这不是直觉。假设我有以下类别: Public Class TestClass Private Shared people As New Dictionary(Of Integer, Person) Class Person Public Property FirstName() As String Public Property LastName As S
Public Class TestClass
Private Shared people As New Dictionary(Of Integer, Person)
Class Person
Public Property FirstName() As String
Public Property LastName As String
Public Sub SayMyName()
MsgBox(FirstName & " " & LastName)
End Sub
Public Sub New(FirstName As String, LastName As String)
Me.FirstName = FirstName
Me.LastName = LastName
End Sub
End Class
Shared Sub Test()
Dim checkPerson As Person = Nothing
With checkPerson
If (Not people.TryGetValue(3, checkPerson)) Then checkPerson = New Person("Bob", "Allen")
.SayMyName()
End With
End Sub
Shared Sub New()
people.Add(1, New Person("John", "Doe"))
people.Add(2, New Person("Jane", "Smith"))
End Sub
End Class
如果调用TestClass.Test()
,则调用SayMyName()
会引发System.NullReferenceException。如果我正在调试,则没有明显的空引用。我最终意识到,这是因为当“with”块启动时引用为null,并且CLR仍然将其视为null,即使调试器显示它存在
显然,为了清晰起见,我的示例进行了简化,但在我的实际代码中,在“with”块之外声明实例方式,然后在块内部有条件地分配它是有用的(即,如果它之前没有在“with”块之外分配)
有人对此有合理的解释吗?我知道我可以很容易地解决这个问题,但我只是好奇人们对这种行为的看法或了解。带有的
块捕获您传递的表达式的当前值,一次。(它将此值存储在编译器生成的隐藏变量中)
如果它按照您希望的方式运行,那么使用SomeSlowFunction()编写将对块中的每一行代码再次调用该函数。该函数的工作原理是取一个表达式并对其求值一次,然后允许您对多个语句使用该表达式
在您的情况下,在这里,当您编写以下内容时:
With checkPerson
If (Not people.TryGetValue(3, checkPerson)) Then checkPerson = New Person("Bob", "Allen")
.SayMyName()
End With
表达式在第一行是checkPerson
。这就相当于做:
' Evaluate the expression
Dim temp = checkPerson
' Perform statements, substituting as required
If (Not people.TryGetValue(3, checkPerson)) Then checkPerson = New Person("Bob", "Allen")
temp.SayMyName()
此行为是经过设计的,旨在避免在昂贵的情况下多次评估表达式,即:
With SomeExpensiveFunctionThatReturnsAnObject()
在以下内容的表达部分中有明确的记录:
计算结果为对象的表达式。表达式可以是任意复杂的,并且只计算一次。表达式可以计算为任何数据类型,包括基本类型
当你写这个--checkPerson=newPerson(“鲍勃”、“艾伦”).SayMyName()
时,它不是将“checkPerson”设置为“SayMyName”的返回值吗?“我很惊讶它能编译。@McGarnagle——它不是一行,而是两行。”。“.SayMyName()”是一个单独的调用。@McGarnagle With块使该调用成为一个完全独立的代码行,与上面的语句无关。在这方面,它的行为与其他语言(如C#)不同。谢谢大家。这很有道理。