【问题标题】:unsubscribing events from class?取消订阅课堂活动?
【发布时间】:2015-06-18 01:53:27
【问题描述】:

我需要一些关于这种场景的最佳实践的建议。我搜索了但没有找到任何令人满意的答案。

我们在 winforms 项目中使用了第 3 方 (.net) DLL。它引发了一些事件,我们订阅了。问题是,我需要在课堂上明确取消订阅这些事件吗?

顺便说一句,我们都使用 .net 框架 4。感谢您的建议。

一些示例代码...

public class MyClientCode: IDisposable
{
   private readonly 3rdParty.TheirClass _theirClass;
   public MyClientCode()
  {
     _theirClass = new _theirClass()
     _theirClass.ReadData += ReadDataEvent;
  }

  public void SomeOtherMethod()
  {
           //some other code
  }

  public void ReadDataEvent()
  {
    //some code
  }

  public void Dispose()
  {
    _theirClass.ReadData -= ReadDataEvent;
  }
}

在按钮点击事件中,我会...

 MyClientCode code = new MyClientCode();
 code.SomeOtherMethod();

【问题讨论】:

  • 不,假设 _theirClass 从未在 MyClientCode 类之外使用。你从来没有把它传出去吗?
  • 是的 _theirClass 是私有的

标签: c# .net


【解决方案1】:

如果不取消订阅,订阅事件的对象将不会被垃圾回收(它会保存在内存中)。这可能会造成内存泄漏并导致内存使用过多。

然而,如果事件的生命周期与包含它的类的生命周期较短或相同,那么在您的情况下,内存将被正确收集。如果您有另一个对象引用非私有事件,那么您将遇到问题。

MSDN:

在您取消订阅某个事件之前,发布对象中作为该事件基础的多播委托具有对封装订阅者事件处理程序的委托的引用。 只要发布对象持有该引用,您的订阅者对象就不会被垃圾回收。

请注意,如果您正在退出您的应用程序,则无需取消订阅,只有在不应该将其保存在内存中的情况下才需要取消订阅。 (例如,当您在应用程序中关闭一个窗口时,您应该取消订阅任何事件,否则该窗口仍将保留在内存中。)如果手动销毁 包含 对象,事件将也被销毁了。

【讨论】:

  • 感谢您的回复。如果我们中的一个人忘记调用 dispose 方法,是否有(自动方式)调用这个 dispose 方法?
  • 没有自动方式,请参阅this 问题,该问题展示了如何在IDisposables 周围使用using 块。
  • 请注意,Cyral 没有提到 Dispose。
  • @JohnSaunders 在 OP 中,他使用 dispose 取消订阅该事件。
  • Cyral,我知道我可以使用“使用”,但我们有几个开发人员可能会使用此代码,并希望确保即使忘记了也可以处理对象。