私はメモリ管理について読んでいて、本もグーグルも正確な答えを考え出していないプロジェクトの状況に出くわしました。デリゲートがオブジェクトを管理し、イベントがデリゲートインスタンスであることはすでに知っています。そうは言っても、アプリケーションが終了すると、デリゲートインスタンスはメモリから削除されます。
私が理解できないのは、クラスが破棄されるまでに(明示的にまたはGCによって)外部コードがすべてのイベント参照を解放したことを確認する方法です。例として、クラスA
はイベントを公開し、クラスB
はそれを消費します。クラス呼び出しデリゲートへの参照を解放せずB
にクラスでDisposeします。A
もちろん、Disposeメソッド自体からエラーをスローすることはできません。
以下は、デリゲートとそれを消費する別のクラスを持つクラスです。
public class ClassB
{
private ClassA A { get; set; }
public ClassB()
{
this.A = new ClassA();
this.A.OnProcessed += new ClassA.DelegateProcessed(this.ClassA_Processed);
}
public void Process()
{
this.A.Process();
}
public void ClassA_Processed (ClassA sender, EventArgs e)
{
// Do something.
// Code written by another developer does not free up events before calling Dispose.
this.A.Dispose();
this.A = null;
}
}
public class ClassA: IDisposable
{
public delegate void DelegateProcessed (A sender, EventArgs e);
public event DelegateProcessed OnProcessed = null;
~ClassA() { this.Dispose(false); }
public void Dispose ()
{
this.Dispose(true);
System.GC.SuppressFinalize(this);
}
private void Dispose (bool disposing)
{
if (!this.Disposed)
{
if (disposing)
{
// Dispose managed resources here.
// Is it possible / advisable to dispose of delegates / events here?
// Will this adversely affect the consumer class?
this.OnProcessed -= new ClassA.DelegateProcessed(this.ClassA_Processed);
}
}
this.Disposed = true;
}
public void Process () { this.OnProcessed(this, new EventArgs()); }
public void ClassA_Processed (ClassA sender, EventArgs e) { }
}
重要なのは、開発者がClassBで何をするかに関係なく、ClassAがガベージコレクションの対象となるようにすることです。重要なのは、消費者が不注意であっても、ClassAがメモリに費やす時間を最小限に抑えることです。
更新:回答から、イベントをClassAから明示的に削除する必要がないことは明らかです。主な質問については、弱参照が以下のように進む方法のようです。目的は、ClassAがメモリに留まる時間を最小限に抑えることです。何か見落とした場合に備えてお知らせください。