System.WeakReferenceが何をするかは理解していますが、理解できないように見えるのは、System.WeakReferenceが何に役立つかを示す実際的な例です。クラス自体は、まあ、ハックのように思えます。私が見た例でWeakReferenceが使用されている場合、問題を解決するためのより良い方法が他にもあるように思われます。本当にWeakReferenceを使用しなければならない場所の標準的な例は何ですか?この種の振る舞いやこのクラスの使用から さらに離れようとしているのではないでしょうか。
4 に答える
便利な例の1つは、DB4Oオブジェクト指向データベースを実行している人たちです。そこでは、WeakReferencesは一種のライトキャッシュとして使用されます。アプリケーションが保持している間だけオブジェクトをメモリに保持し、実際のキャッシュを最上位に置くことができます。
もう1つの用途は、弱いイベントハンドラーの実装です。現在、.NETアプリケーションでのメモリリークの大きな原因の1つは、イベントハンドラーの削除を忘れていることです。例えば
public MyForm()
{
MyApplication.Foo += someHandler;
}
問題がわかりますか?上記のスニペットでは、MyApplicationがメモリ内で存続している限り、MyFormはメモリ内で永久に存続します。10個のMyFormを作成し、それらをすべて閉じます。10個のMyFormは引き続きメモリに残り、イベントハンドラによって存続します。
WeakReferenceと入力します。WeakReferencesを使用して弱いイベントハンドラーを作成し、someHandlerがMyApplication.Fooに対する弱いイベントハンドラーになるようにして、メモリリークを修正できます。
これは単なる理論ではありません。DidItWith.NETブログのDustinCampbellは、 System.WeakReferenceを使用した弱いイベントハンドラーの実装を投稿しました。
これを使用して、未使用のエントリが自動的にガベージコレクションされるキャッシュを実装します。
class Cache<TKey,TValue> : IEnumerable<KeyValuePair<TKey,TValue>>
{ Dictionary<TKey,WeakReference> dict = new Dictionary<TKey,WeakReference>();
public TValue this[TKey key]
{ get {lock(dict){ return getInternal(key);}}
set {lock(dict){ setInteral(key,value);}}
}
void setInteral(TKey key, TValue val)
{ if (dict.ContainsKey(key)) dict[key].Target = val;
else dict.Add(key,new WeakReference(val));
}
public void Clear() { dict.Clear(); }
/// <summary>Removes any dead weak references</summary>
/// <returns>The number of cleaned-up weak references</returns>
public int CleanUp()
{ List<TKey> toRemove = new List<TKey>(dict.Count);
foreach(KeyValuePair<TKey,WeakReference> kv in dict)
{ if (!kv.Value.IsAlive) toRemove.Add(kv.Key);
}
foreach (TKey k in toRemove) dict.Remove(k);
return toRemove.Count;
}
public bool Contains(string key)
{ lock (dict) { return containsInternal(key); }
}
bool containsInternal(TKey key)
{ return (dict.ContainsKey(key) && dict[key].IsAlive);
}
public bool Exists(Predicate<TValue> match)
{ if (match==null) throw new ArgumentNullException("match");
lock (dict)
{ foreach (WeakReference weakref in dict.Values)
{ if ( weakref.IsAlive
&& match((TValue) weakref.Target)) return true;
}
}
return false;
}
/* ... */
}
ミックスインでの状態保持には弱参照を使用します。ミックスインは静的であるため、静的オブジェクトを使用して状態を非静的オブジェクトにアタッチする場合、それがどれくらいの期間必要になるかはわかりません。そのため、 a を保持する代わりに、 mixin が長時間ドラッグするのを防ぐためにaDictionary<myobject, myvalue>
を保持します。Dictionary<WeakReference,myvalue>
唯一の問題は、アクセスするたびに、無効な参照もチェックして削除することです。もちろん、何千人もいない限り、誰かを傷つけるわけではありません。