編集: Joel Coehoornsの優れた回答の後、より具体的にする必要があることを理解したので、理解しようとしていることに近づけるようにコードを変更しました...
イベント:私が理解しているように、バックグラウンドでのイベントは、イベントが発生したときに実行されるEventHandlers(別名デリゲート)の「コレクション」です。つまり、私にとっては、オブジェクトYにイベントEがあり、オブジェクトXがイベントYEにサブスクライブしている場合、YはXを参照することになります。これは、 YがXにあるメソッドを実行する必要があるため、Xを収集できないためです。私が理解していること。
//Creates reference to this (b) in a.
a.EventHappened += new EventHandler(this.HandleEvent);
しかし、それはJoelCoehoornが言っていることではありません...
ただし、イベントには問題があり、イベントのあるタイプでIDisposableを使用したい場合があります。問題は、タイプXが別のタイプYのイベントをサブスクライブすると、XがYへの参照を持つようになることです。この参照により、Yが収集されなくなります。
XがYをどのように参照するのかわかりません???
私の例を少し修正して、私のケースをより詳しく説明しました。
class Service //Let's say it's windows service that must be 24/7 online
{
A _a;
void Start()
{
CustomNotificationSystem.OnEventRaised += new EventHandler(CustomNotificationSystemHandler)
_a = new A();
B b1 = new B(_a);
B b2 = new B(_a);
C c1 = new C(_a);
C c2 = new C(_a);
}
void CustomNotificationSystemHandler(args)
{
//_a.Dispose(); ADDED BY **EDIT 2***
a.Dispose();
_a = new A();
/*
b1,b2,c1,c2 will continue to exists as is, and I know they will now subscribed
to previous instance of _a, and it's OK by me, BUT in that example, now, nobody
references the previous instance of _a (b not holds reference to _a) and by my
theory, previous instance of _a, now may be collected...or I'm missing
something???
*/
}
}
class A : IDisposable
{
public event EventHandler EventHappened;
}
class B
{
public B(A a) //Class B does not stores reference to a internally.
{
a.EventHappened += new EventHandler(this.HandleEventB);
}
public void HandleEventB(object sender, EventArgs args)
{
}
}
class C
{
public C(A a) //Class B not stores reference to a internally.
{
a.EventHappened += new EventHandler(this.HandleEventC);
}
public void HandleEventC(object sender, EventArgs args)
{
}
}
編集2:わかりました。サブスクライバーがパブリッシャーイベントをサブスクライブするときに、サブスクライバー内のパブリッシャーへの参照が作成されないことは明らかです。(EventHandlerを介して)作成されたパブリッシャーからサブスクライバーへの参照のみ...この場合、サブスクライバーの前にGCによってパブリッシャーが収集された場合(サブスクライバーの存続期間はパブリッシャーよりも長い)、問題はありません。
しかし...私が知っているように、GCがいつパブリッシャーを収集するかは保証されていないため、理論的には、サブスクライバーの有効期間がパブリッシャーよりも長い場合でも、サブスクライバーは収集に合法である可能性がありますが、パブリッシャーはまだ収集されません(私は最も近いGCサイクル内で、GCが最初にパブリッシャーを収集し、次にサブスクライバーを収集するのに十分スマートであるかどうかを確認します。
とにかく、そのような場合、私のサブスクライバーはパブリッシャーへの直接参照を持たず、イベントのサブスクライブを解除できないため、パブリッシャーにIDisposableを実装させて、彼へのすべての参照を削除する前にIDisposableを破棄したいと思います(私の例)。
AND AGAINサブスクライバーへのすべての参照をクリアするために、パブリッシャーのdisposeメソッドに何を書き込む必要がありますか?EventHappened-=nullである必要があります。またはEventHappened=null; またはそのような方法でそれを行う方法はありません、そして私は以下のようなものを作る必要があります???
public event EventHandler EventHappened
{
add
{
eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] + value;
}
remove
{
eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] - value;
}
}