C# で弱参照を使用したい場合の方法メモ
目的
- インスタンスへの参照は保持したいが、強い参照を持ってGCの回収対象にならないのを避けたい
- 循環参照の回避
- コンポジションしている子のインスタンスから親のインスタンスを参照したい場合
- => ただもし、ViewModel => Viewの操作で考えてるなら、Messenger パターン使ったほうが良い
使い方
var wref = new WeakReference<Hoge>(new Hoge);
Hoge obj;
if (wref.TryGetTarget(out obj))
{
// 参照が必要な処理
}
WeakReference<T>.TryGetTarget(out obj)
は取得成功/失敗をboolean型で返す。
注意点として、強い参照の保持期間は当然ながら、if式の間だけではなく、上記の例でいうと取得後、obj
が破棄されるまでになる。一時変数ではなく、長い生存期間をもつ変数が束縛してしまうと弱参照で持った意味がなくなる。
メモ
WeakReference<T>
は、.NET Framework 4.5
以降で使用可能。
それ以前は WeakReference
がつかえたが、書き方によってはGCで回収された後に参照できる方法がとれてしまった。
そこらへんは以下の記事が詳しい。
WeakReference・WeakReference の違いと、そこに潜む罠 - Qiita
WeakReference<T>
は、TryGetTarget
の文法上、使用中は強い参照を持つことが強制されるため上記の問題は解決された。
どうやって実現されているか
TODO: WeakReference<T>
は内部的に IntPtr
で持っているとかなんとかの記事を見かけたことがあるけれども、その記事が見当たらないのと正確かどうかがわからないので追記する
C# 7.0から
出力変数宣言
C# 7 の新機能 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C
C# 7.0
からは、新しい文法として出力変数宣言
が使えるため、書き方が簡略化できるようです。
if (wref.TryGetTarget(out var obj))
{
// 参照が必要な処理
}
参考
WeakReference(T) クラス (System)
【雑記】弱参照 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C
【.NET】弱いつながりでWeakReference | 創造的プログラミングと粘土細工