我有这段代码
public class Publisher
{
public event EventHandler SomeEvent;
}
public class Subscriber
{
public static int Count;
public Subscriber(Publisher publisher)
{
publisher.SomeEvent += new EventHandler(publisher_SomeEvent);
}
~Subscriber()
{
Subscriber.Count++;
}
private void publisher_SomeEvent(object sender, EventArgs e)
{
// TODO
}
}
在我的应用程序的主要方法中,我有
static void Main(string[] args)
{
Publisher publisher = new Publisher();
for (int i = 0; i < 10; i++)
{
Subscriber subscriber = new Subscriber(publisher);
subscriber = null;
}
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(Subscriber.Count.ToString());
}
如果我运行它,我将有 0 作为输出。如果我从代码中删除事件订阅,我会得到预期的结果——即 10。
当GC.Collect()被调用时,gc 被强制启动垃圾收集。因为 Subscriber在其中定义了Finalize,GC 将暂停收集,直到finalizequeue为空——也就是说,所有 Subscription 实例都会调用它的Finalize()方法(如果我的假设是错误的,请纠正我)。在下一行GC.WaitForPendingFinalizers()被调用,这将有效地暂停执行,直到终结器队列为空。现在,因为我们有 0 作为输出,我相信Finalize()没有被调用,这让我相信 GC 没有将订阅者实例标记为要收集,因此Finalizer()方法没有被调用。
所以我有2个问题
- 我的假设是否正确并且事件订阅会阻止 GC 标记要收集的订阅者实例?
- 如果是这样,是因为发布者持有对订阅者的引用吗?(垃圾收集器和事件处理程序)
我唯一的猜测是,由于有 10 个 Subscriber 实例引用同一个发布者实例,当 GC 收集发生时,它看到还有其他对发布者的引用,因此无法收集,结果所有订阅与发布者一起的实例正在移动到下一代,因此在代码执行到达Console.WriteLine(Subscriber.Count.ToString())时不会发生垃圾收集,也不会调用Finalize( )
我是对的还是我在这里遗漏了什么?