//Creates reference to this (b) in a.
a.EventHappened += new EventHandler(this.HandleEvent);
但这并不是Joel Coehoorn所说的内容...
然而,与事件相关的问题在于有时人们想要将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)。
再次强调:我应该在发布者的Dispose方法中写些什么,以清除所有对订阅者的引用?应该是EventHappened -= null;还是EventHappened = null;或者没有办法以这种方式做到,我需要像下面一样做些什么?
public event EventHandler EventHappened
{
add
{
eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] + value;
}
remove
{
eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] - value;
}
}