编辑:在 Joel Coehoorns 出色的回答之后,我明白我需要更具体,所以我修改了我的代码以更接近我想要理解的东西......
事件:据我了解,在后台,事件是 EventHandlers aka Delegates 的“集合”,将在事件引发时执行。所以对我来说这意味着如果对象Y有事件 E 并且对象 X 订阅了事件YE,那么Y将引用 X,因为Y必须执行位于 X 中的方法,这样,X 就不能被收集,并且我明白的事情。
//Creates reference to this (b) in a.
a.EventHappened += new EventHandler(this.HandleEvent);
但这不是乔尔·科霍恩所说的……
但是,事件存在一个问题,有时人们喜欢将 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,以便在删除对他的所有引用之前将其处理(参见 CustomNotificationSystemHandler 中的我的例子)。
再一次,我应该在发布者处理方法中写什么以清除对订阅者的所有引用?应该是 EventHappened -= null; 或 EventHappened = null; 或者没有办法以这种方式做到这一点,我需要做类似下面的东西???
public event EventHandler EventHappened
{
add
{
eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] + value;
}
remove
{
eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] - value;
}
}