参照型の通常の期待されるセマンティクスは、オブジェクト識別子として動作する必要があるということです。プログラムが作成した 5483 番目のオブジェクトへの参照を変数が保持している場合、その変数をメソッドに渡すと、5483 番目のオブジェクトへの参照が与えられます。VB.NET はほとんどこのように動作しますが、興味深い例外があります:Option Strict On
方言でも、その型の変数Object
をその型のパラメーターを取るメソッドに渡そうとしたり、あるObject
変数を別の変数にコピーしたり、そうでなければ "rvalueObject
その型の「左辺値」に格納される [C 用語を借りる] 型の " は、コンパイラが別のオブジェクトへの参照を格納する結果になることがあります。
コードが扱っているオブジェクトのタイプを知らず、気にする必要がない場合に、これを回避する良い方法はありますか?
関連するオペランドのいずれかを 以外の型にすることができれば、Object
問題はありません。 ジェネリック メソッド内では、そのジェネリック型の変数は、その型がたまたま であっても正しく機能しますObject
。ただし、ジェネリック型のパラメーターは、Object
その型を使用して型が呼び出された場合と同様に扱われます。
次の方法を検討してください。
Function MakeNewWeakReference(Obj As Object) As WeakReference
Return New WeakReference(Obj)
End Function
Function GetWeakReferenceTargetOrDefault(WR as WeakReference, DefaultValue as Object) _
As Object
Dim WasTarget as Object = WR.Target
If WasTarget IsNot Nothing Then Return WasTarget
Return DefaultValue
End Function
最初の関数は、渡されたオブジェクトが存在する限り存続する WeakReference を返すと予想されます。さらに、2 番目の関数にまだ生きている WeakReference が与えられた場合、メソッドはその関数を生きたままにする参照を返すことが期待されます。残念ながら、参照がボックス化された非プリミティブ値型を参照している場合、その仮定は失敗します。その場合、最初のメソッドは、元の参照によって保持されないボックス化された値の新しいコピーへの弱い参照を返し、2 番目のメソッドは、ボックス化された値の新しいコピーを返します。弱参照の 1 つが生きています。
メソッドをジェネリックに変更した場合:
Function MakeNewWeakReference(Of T As Class)(Obj As T) As WeakReference
Return New WeakReference(Obj)
End Function
Function GetWeakReferenceTargetOrDefault(Of T As Class)(WR as WeakReference, _
DefaultValue as T) As T
Dim WasTarget as T = TryCast(WR.Target, T)
If WasTarget IsNot Nothing Then Return WasTarget
Return DefaultValue
End Function
またはを呼び出す場合でも、メソッド内の問題を回避できます。残念ながら、いずれかのメソッドを type のパラメーターで使用しようとして、格納されているもの (最初のケース) または格納されている変数 (2 番目のケース) も typeであった場合、問題は依然として発生します。メソッドの呼び出し時または戻り値の格納時に発生します。すべてのコードをジェネリック クラスに入れ、それを Object の型パラメーターでのみ使用した場合、常に型のものをジェネリック型にするようにします (そのような操作は、たまたまジェネリック型がMakeNewWeakReference(Of Object)
GetWeakReferenceTargetOrDefault(Of Object)
Object
Object
TryCast
Object
Object
)それは問題を解決するのに役立ちますが、かなり醜いでしょう. 変数が任意のタイプのヒープオブジェクトへの参照を保持できるようにする必要があることを指定する明確な方法はありますが、Object
他のすべての参照タイプと同じように常に参照セマンティクスで動作する必要がありますか?
ところで、いくつかの直接実行可能なテスト コード:
Sub ObjTest(O1 As Object)
Debug.Print("Testing type {0} (value is {1})", O1.GetType, O1)
Dim O2 As Object
Dim wr As New WeakReference(O1)
O2 = O1 ' source and destination are type Object--not identity preserving
Debug.Print("Ref-equality after assignment: {0}", O2 Is O1)
Debug.Print("Ref-equality with itself: {0}", Object.ReferenceEquals(O1, O1))
GC.Collect()
Debug.Print("Weak reference still alive? {0}", wr.IsAlive)
Debug.Print("Value was {0}", O1) ' Ensure O1 is still alive
End Sub
Sub ObjTest()
ObjTest("Hey")
ObjTest(1)
ObjTest(1D)
End Sub
ObjTest(Object)
メソッドに与えられたオブジェクトの型が与えられたオブジェクトの種類を気にする必要がある本当の理由はありませんがtrue
、クラスオブジェクトのようなString
またはプリミティブ値の型で出力される3つのテストはすべてInt32
、非プリミティブな値の型で失敗しますDecimal
. それを修正する良い方法はありますか?