私が非常に不変な型を持っている場合 (すべてのメンバーは読み取り専用であり、それらが参照型のメンバーである場合、それらは非常に不変なオブジェクトも参照します)。
次のように、型に遅延初期化プロパティを実装したいと思います。
private ReadOnlyCollection<SomeImmutableType> m_PropName = null;
public ReadOnlyCollection<SomeImmutableType> PropName
{
get
{
if(null == m_PropName)
{
ReadOnlyCollection<SomeImmutableType> temp = /* do lazy init */;
m_PropName = temp;
}
return m_PropName;
}
}
私が言えることから:
m_PropName = temp;
...スレッドセーフです。両方のスレッドが同時に初期化するために競合することについてはあまり心配していません。これはめったにないためです。論理的な観点からは両方の結果が同じであり、ロックがない場合はロックを使用したくないからです。に。
これは機能しますか?長所と短所は何ですか?
編集: 回答ありがとうございます。おそらくロックを使用して先に進みます。しかし、コンパイラが temp 変数が不要であることを認識し、m_PropName に直接代入する可能性を誰も持ち出さなかったことに驚いています。その場合、読み取りスレッドは、構築が完了していないオブジェクトを読み取る可能性があります。コンパイラはそのような状況を防ぎますか?
(回答は、ランタイムがこれを許可しないことを示しているようです。)
編集:そこで、Joe Duffy によるこの記事に 触発された Interlocked CompareExchange メソッドを使用することにしました。
基本的:
private ReadOnlyCollection<SomeImmutableType> m_PropName = null;
public ReadOnlyCollection<SomeImmutableType> PropName
{
get
{
if(null == m_PropName)
{
ReadOnlyCollection<SomeImmutableType> temp = /* do lazy init */;
System.Threading.Interlocked(ref m_PropName, temp, null);
}
return m_PropName;
}
}
これにより、このオブジェクト インスタンスでこのメソッドを呼び出すすべてのスレッドが同じオブジェクトへの参照を取得するようになるため、== 演算子が機能します。無駄な作業が発生する可能性がありますが、これは問題ありません。楽観的なアルゴリズムになるだけです。
以下のコメントにあるように、これは動作する .NET 2.0 メモリ モデルに依存します。それ以外の場合、m_PropName は volatile と宣言する必要があります。