【发布时间】:2012-07-16 15:37:43
【问题描述】:
编辑:在 Joel Coehoorns 出色的回答之后,我明白我需要更具体,所以我修改了我的代码以更接近我想要理解的东西......
事件: 据我了解,在后台,事件是 EventHandlers 又名委托的“集合”,当事件引发时将被执行。所以对我来说,这意味着如果对象 Y 有事件 E 并且对象 X 订阅了事件 Y.E,那么 Y 将引用 X,因为Y必须执行位于X的方法,那样X不能被收集,那我明白了。
//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 中)。
再一次 我应该在发布者处理方法中写什么以清除对订阅者的所有引用?应该是 EventHappened -= null;或 EventHappened = null;或者没有办法以这种方式做到这一点,我需要做类似下面的东西???
public event EventHandler EventHappened
{
add
{
eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] + value;
}
remove
{
eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] - value;
}
}
【问题讨论】:
-
这不是那个问题的重复。
-
问题是什么?你有太多的编辑,所以我不明白讨论的主题是什么。请在不在顶部的问题按钮上添加编辑,并且不要删除初始问题。
标签: c# .net events garbage-collection dispose