【问题标题】:C# Dispose(), unsubscribe from eventsC# Dispose(),取消订阅事件
【发布时间】:2017-04-25 11:36:14
【问题描述】:

在这种情况下是否可以立即调用 dispose 和取消订阅事件? context_ 用于管理一个简单的状态机,我们基本上通过创建一个新状态机来启动和停止它。

class ClassA
{

      StateContext context_;

      void SomeMethod()
      {
         if(context_ != null)
            context_.Dispose();

            context_ = new StateContext();

      }

   class StateContext : IDisposable
   {
        SubClassA()
        {
            //Subscribe to an event
        }   

        void Dispose()
        {
            //unsubscribe to an Event
        }
    }

}

【问题讨论】:

  • 不,您违反了 IDisposable 合同。违反合同需要额外的关注和大量评论。只要课程不公开,您就可以逍遥法外。
  • 如果实际代码真的很像示例代码,你真的可以简单地将Dispose变成Unsubscribe,而不是实现IDisposable,并且仍然有相同的行为而不需要问“我是不是允许制作符合我想要的逻辑的方法"

标签: c# events idisposable unsubscribe


【解决方案1】:

除了调用Dispose 之外,行为良好的对象不需要进行清理。如果一个对象订阅了可能比它寿命更长的其他对象的事件,它必须(为了表现良好)确保以某种方式清理这些事件。这可以通过使用弱事件或让Dispose 处理事件订阅来完成。

请注意,术语“非托管资源”与术语“非托管代码”的关系很小,并且来自长期存在的对象的正常事件是非托管资源。因此,即使事件与非托管代码无关,使用IDisposable 清理它们也是完全正确和正确的。事实上,我建议这种清理应该被认为是强制性的,除非存在其他方法来确保清理(例如,事件由弱事件管理器处理,或者其事件被订阅的对象不会超过订阅者)。 WinForms 代码通常是草率的,假设事件发布者不会比订阅者更长寿,但这并不意味着这种草率应该被认为是可取的。

【讨论】:

  • “来自长寿命对象的正常事件是非托管资源”这是不正确的;区分非托管资源和托管资源的原因是,在终结期间,接触托管资源可能不安全,因为这些对象可能已经终结。触摸我们订阅的对象可能不安全,以便在完成期间取消订阅。因此,只有在 disposing 为 true 时才应取消订阅。
  • @TamaMcGlinn:托管资源和非托管资源之间的区别基于放弃是否会导致最终履行义务(可能通过最终确定)或最终不履行。如果一个对象从一个长期存在的对象订阅了一个正常的事件,那么它不会被终结,直到它取消订阅或者直到长期存在的对象有资格被终结。如果在程序退出之前长期存在的对象永远不会有资格完成,那么事件订阅者也不会。
  • @supercat 是否意味着我们应该覆盖我们类中的Finalize(即~),并将unsubscribe() 放在IDisposable Pattern 中的“非托管资源”部分?
  • @joe:Finalize 通常不适用于事件,因为事件订阅者在事件发布者的生命周期内没有资格完成最终化,并且在发布者死后订阅将变得毫无意义。
  • @supercat 我明白了。因此,当有临时订阅者订阅长期发布者时,我们应该始终显式调用 Disposeunsubscribe
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-05
  • 1970-01-01
  • 2020-01-01
  • 2020-11-11
  • 2018-07-21
  • 2020-02-06
  • 1970-01-01
相关资源
最近更新 更多