2

.NET で非常に奇妙な動作をしていることに気付きました。何が起こっているのかを理解するのに少し時間がかかりました。私にとっては直感的ではないからです。次のクラスがあるとします。

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()の呼び出しによって System.NullReferenceException がスローされSayMyName()ます。私がデバッグしている場合、明らかな null 参照はありません。「with」ブロックが開始されたときに参照がnullであり、デバッガーが存在することを示していても、CLRによってまだそのように扱われているためであることに最終的に気付きました。

明らかに、私のサンプルはわかりやすくするために単純化されていますが、私の実際のコードでは、「with」ブロックの外側でインスタンスを宣言し、条件付きでブロック内に割り当てると便利です (つまり、「With」の外側で以前に割り当てられていなかった場合)。ブロック)。

誰もこれについて合理的な説明を持っていますか? これを簡単に回避できることはわかっていますが、この動作について人々がどう考えているか、または知っているかを知りたいだけです。

4

2 に答える 2

6

With block式を取得して一度評価することで機能し、それを複数のステートメントに使用できるようにします。

あなたの場合、ここで、これを書くとき:

With checkPerson
    If (Not people.TryGetValue(3, checkPerson)) Then checkPerson = New Person("Bob", "Allen")
    .SayMyName()
End With

checkPerson1 行目にあります。これは、次のことと同等になります。

' 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()

With ドキュメントの式セクションで明確に文書化されています。

オブジェクトに評価される式。式は任意に複雑にすることができ、一度だけ評価されます。式は、基本型を含む任意のデータ型に評価できます。

于 2013-10-11T18:44:31.947 に答える
3

Withブロックは、渡された式の現在の値を 1 回キャプチャします。(この値は、コンパイラによって生成された隠し変数に格納されます)

意図したとおりに動作した場合With SomeSlowFunction()、ブロック内のコード行ごとに関数を再度呼び出すことになります。

于 2013-10-11T18:44:25.793 に答える