【发布时间】:2012-09-24 13:58:19
【问题描述】:
我一直在阅读有关内存管理的内容,并且在一个项目中遇到了这样的情况,即这本书和谷歌都没有给出确切的答案。我已经知道委托是管理对象,事件是委托实例。话虽如此,一旦应用程序结束,委托实例将从内存中删除。
我想不通的是如何确保在我的类被释放时(显式地或通过 GC)外部代码已释放所有事件引用。例如,A 类公开一个事件,B 类使用它。 B 类在 A 类上调用 Dispose,而不释放对委托的引用。当然,我们不能从 Dispose 方法本身抛出错误。
下面是一个类,它有一个委托和另一个消费它的类。
public class ClassB
{
private ClassA A { get; set; }
public ClassB()
{
this.A = new ClassA();
this.A.OnProcessed += new ClassA.DelegateProcessed(this.ClassA_Processed);
}
public void Process()
{
this.A.Process();
}
public void ClassA_Processed (ClassA sender, EventArgs e)
{
// Do something.
// Code written by another developer does not free up events before calling Dispose.
this.A.Dispose();
this.A = null;
}
}
public class ClassA: IDisposable
{
public delegate void DelegateProcessed (A sender, EventArgs e);
public event DelegateProcessed OnProcessed = null;
~ClassA() { this.Dispose(false); }
public void Dispose ()
{
this.Dispose(true);
System.GC.SuppressFinalize(this);
}
private void Dispose (bool disposing)
{
if (!this.Disposed)
{
if (disposing)
{
// Dispose managed resources here.
// Is it possible / advisable to dispose of delegates / events here?
// Will this adversely affect the consumer class?
this.OnProcessed -= new ClassA.DelegateProcessed(this.ClassA_Processed);
}
}
this.Disposed = true;
}
public void Process () { this.OnProcessed(this, new EventArgs()); }
public void ClassA_Processed (ClassA sender, EventArgs e) { }
}
关键是要确保无论开发人员对 ClassB 做什么,ClassA 都有资格进行垃圾回收。关键是尽量减少 ClassA 在内存中花费的时间,即使消费者粗心。
更新:从答案中可以清楚地看出,事件不必从 ClassA 中显式删除。至于主要问题,弱引用似乎是下面回答的方法。目标是最小化 ClassA 在内存中的停留时间。如果我忽略了任何事情,请告诉我。
【问题讨论】:
-
这里的逻辑有些前后矛盾。在
OnProcessed的调用列表中,A 类将持有 B 类的代表,反之亦然。 -
@spender:我在 SO 编辑器中编写了代码,因此可能存在错误,但我不理解您的观点。 ClassA 是具有委托的,而 ClassB 持有引用。我试图从 ClassA 中删除引用,这样即使 ClassB 忘记了,ClassA 也有资格进行垃圾收集。如果您发现错误,请告诉我,我会做必要的。
-
您可以安全地让 A 类的实例超出范围,而无需我们在您的代码中看到的任何东西通过委托实例保留它。但是,在您的代码中,如果您让 B 的实例超出范围,它将不会被收集,因为在您的实例中,
ClassA_Processed的调用列表中保留了一个指向方法ClassA_Processed的委托A类 -
客户端程序员会期望在他处理您的对象后您将停止引发事件。不要让他失望。
-
那是肯定的@HansPassant。代码 sn-p 仅用于说明。在生产环境中,disposed 被跟踪,线程安全的委托实例也是如此。
标签: c# .net events delegates idisposable