いまさらコンナコト の続き。
んなわけで、eventに登録されたdelegateは強参照なのでガベコレされない。
そんじゃまーeventにdelegateの弱参照を登録してみるテスト:
using System;
using System.Collections.Generic;
delegate void Update();
class Speaker {
private List<WeakReference> delegates_ = new List<WeakReference>();
public event Update OnUpdate {
add { delegates_.Add(new WeakReference(value)); }
remove {} // removeの必要なし。
}
public void Notify() {
List<WeakReference> tmp = new List<WeakReference>();
foreach ( WeakReference wref in delegates_ ) {
if ( wref.IsAlive ) { // 参照が有効(死んでない)なら
tmp.Add(wref); // tmpに追加して
((Update)wref.Target)(); // 着火する
}
}
delegates_ = tmp; // 死んだ参照を取り除く
}
}
class Listener {
// 現状維持...
}
class Program {
public static void Main() {
Speaker s = new Speaker();
for ( int i = 0; i < 1000; ++i ) {
Listener l = new Listener();
s.OnUpdate += l.Listen;
s.Notify();
}
}
}
System.WeakReferenceはオブジェクトを捕まえることがないので
好きに死ぬことができます。そんときWeakReference.IsAliveがfalse
となることで死んだ参照であることが知れるわけすね。
あ、wref.IsAlive なら tmpにAddののち着火してんだけど、
この間に死んじゃうことってあるんでしょか? あるんなら、
「Notify()が終わるまで死んじゃダメ!」って言うには
どぉすりゃいいんです? 教えてえらいひと。