不変オブジェクトを含むいくつかの状況では、意味的に同一である多くの別個のオブジェクトが存在する可能性があります。簡単な例は、ファイルから文字列にテキストの多くの行を読み取ることです。プログラムの観点からは、2行が同じ文字シーケンスを持っているという事実は「一致」ですが、プログラマーの観点からは、大量の重複が予想される場合があります。多くの文字列インスタンスが同一である場合、それらの個別のインスタンスへの参照を単一のインスタンスへの参照に変更すると、メモリが節約され、それらの間の比較も容易になります(2つの文字列参照が同じ文字列を指している場合、文字を入力する必要はありません-それらが同一であることを決定するための文字ごとの比較)。
一部のシナリオでは、システムが提供する文字列インターン機能が役立つ場合があります。ただし、いくつかの厳しい制限があります。
- 文字列がインターンされると、そのインターンされたコピーは、その文字列への他の参照が存在するかどうかに関係なく、永久に存続します。
- 文字列インターン機能は文字列でのみ機能し、他の不変のタイプでは使用できません。
trueが存在する場合WeakDictionary<ImmutableClassType, ImmutableClassType>
(各要素について、キーと値は同一になります)、コードは次のようになります。
if (theDict.TryGetValue(myString, ref internedString))
myString = internedString;
else
theDict[myString] = myString;
残念ながら、私はWeakDictionary<keyType, valType>
.netに組み込まれているクラスを知りません。さらに、両方の参照が常に同じものを指している場合、各アイテムのキーと値の弱参照を生成するのは無駄に思えます。
についていくつか読んだConditionalWeakTable
ことがありますが、それは興味深いクラスのように聞こえますが、目的は1つのインスタンスを取得して、意味的に同等の別の独立したインスタンスを見つけることができるため、ここでは使用できないと思います。
クラスのインスタンスの有効期間が明確に定義されている状況では、従来の方法を使用してDictionary
同一のインスタンスをマージするのが妥当な場合があります。Dictionary
ただし、多くの場合、そのようなものをいつ放棄するか、またはその中のアイテムをクリーンアップする必要があるかを知るのは難しい場合があります。ベースのWeakReference
インターンコレクションは、そのような問題を回避します。そのようなものは存在しますか、それとも簡単に実装できますか?
補遺
svickが指摘したように、ライブでターゲットの値を返し、デッドでその値を返し続けるをDictionary<WeakReference, WeakReference>
定義する実用的な方法がないため、aはやや問題があります。整数のターゲットハッシュコード値(コンストラクターで設定)を含み、その整数を返す構造体を定義できます。わずかな改善は、を使用して、削除のためにテーブルアイテムをキューに入れるために使用できるファイナライズ可能なオブジェクトにターゲットをリンクすることです。IEqualityComparer
WeakReference
GetHashCode
GetHashCode
ConditionalWeakTable
WeakReference
辞書を熱心にクリーンアップしようとすることと、やや受動的なアプローチを取ること(たとえば、最後のスイープ以降に少なくとも1つのGCがあった場合にアイテムを追加するときにスイープを実行することと、最後のスイープ以降に追加されたアイテムの数が、それを生き残ったアイテムの数を超えています)。辞書内のすべてをスイープすることは無料ではありませんが、ConditionalWeakTableもおそらく無料ではありません。
PPS
私が考えていた別の概念ですが、弱いインターンのアプローチほど有用ではなく、論理的に不変の型に可変の「タイムスタンプ」値を保持させ、によるその引数ref
。2つの異なるインスタンスが等しいことが判明した場合、それらのタイムスタンプ値が調べられます。両方がゼロの場合、グローバルカウンター(-1、-2、-3など)から連続した負の数が割り当てられます。低いタイムスタンプ値を持っていた(または割り当てられた)パラメータは、他のパラメータに置き換えられます。
このようなアプローチを使用すると、多くのオブジェクトインスタンスが繰り返し比較された場合、参照の多くが「古い」インスタンスへの参照に置き換えられます。使用パターンによっては、これにより、インターンディクショナリを使用せずに、ほとんどの同一のオブジェクトインスタンスがマージされる場合があります。ただし、ネストされたオブジェクトにこのようなアプローチを適用するには、「不変」オブジェクトを使用して、ネストされたオブジェクトの参照を変更して、他のおそらく同一のネストされたオブジェクトを指すようにする必要があります。「おそらく同一の」オブジェクトが常にそうである場合、これは問題ないはずですが、そうでない場合、かなり奇妙な誤動作を引き起こす可能性があります。