简体   繁体   English

使用 IDisposable 取消订阅事件——我是否需要在 dispose 中放入其他东西?

[英]Using IDisposable to unsubscribe an event— do I need to put other things inside the dispose?

I have the following class我有以下课程

public class Presenter: IDisposable
{
   public IView View
   {get;private set;}

   //snip other object reference, all managed
   public Presenter(IView view)
  {
     View=view;
     View.MouseUp += MouseUpEvent;
  }

  public void MouseUpEvent()
  {
    //do whatever you want to do on mouse up
  }

  public void Dispose()
  {
    View.MouseUp -= MouseUpEvent;
    // no more manual disposing
  }
}

The question now is, am I implement Dispose() method correctly?现在的问题是,我是否正确实现了Dispose()方法? Or do I need to manually dispose all the other managed objects just because I have explicilty define Dispose() ?或者我是否需要手动处理所有其他托管对象只是因为我明确定义了Dispose()

I reckon that the GC is smart enough to do its own disposing ( except the event subscription) even without me manually doing it.我认为即使没有我手动执行,GC 也足够聪明,可以自行处理(事件订阅除外)。 Am I right?我说得对吗?

If you go with the choice of subscribing in the constructor, then this looks reasonable.如果您选择在构造函数中订阅,那么这看起来很合理。 I would echo Josh's sentiments that it may not be the best approach.我赞同 Josh 的观点,即这可能不是最好的方法。 On the other hand, it may be the simplest way of achieving your goal, which is always a good thing.另一方面,它可能是实现目标的最简单方法,这总是一件好事。 I'm not going to pretend to be an expert on UI patterns: having raised the concern, I'll assume that this is the way you want to work, and address the question itself :)我不会假装自己是 UI 模式方面的专家:提出问题后,我会假设这是您想要的工作方式,并自行解决问题:)

I personally find Josh's prescribed pattern 1 overly complex for simple scenarios - your approach is fine, with just one change: make your class sealed.我个人认为 Josh 规定的模式1对于简单场景过于复杂 - 您的方法很好,只需进行一项更改:使您的课程密封。 If you don't want to seal the class, you should go for the Dispose(bool) option (but without the finalizer) because subclasses may also need to dispose of things, and may need a finalizer.如果你不想密封类,你应该去的Dispose(bool)选项(但没有终结),因为子类可能还需要处理的事情,可能需要一个终结。 Without the possibility of a derived type, life is simpler (as it so often is).没有派生类型的可能性,生活会更简单(因为它经常如此)。

You don't need to do anything with other members just because you now implement IDiposable for that one reason.不需要做其他任何成员,只是因为你现在实现IDiposable的原因之一。

So, do you need to derive any further from this class?那么,您是否需要从这个类进一步派生?


1 I do understand that this is the standard recommended pattern, although I'd recommend that you read the advice of Joe Duffy et al for even more details - it can all get very complicated. 1我确实理解这是标准的推荐模式,尽管我建议您阅读Joe Duffy 等人的建议以了解更多详细信息 - 它可能会变得非常复杂。

Personally, I would avoid hooking/unhooking the event in the constructor and dispose.就个人而言,我会避免在构造函数中挂钩/取消挂钩事件并进行处置。 Instead I would add code to the View get/set accessors and add them there.相反,我会将代码添加到 View get/set 访问器并将它们添加到那里。 But if the Presenter is disposed while a View is attached, I would not bother trying to clean that up.但是,如果在附加视图时处理了演示者,我就不会费心去清理它。 You can explicitly detach the View from the presenter if you need explicit detaching.如果您需要显式分离,您可以从演示者中显式分离视图。

Having said that, here's what I know about IDisposable.话虽如此,这就是我对 IDisposable 的了解。

The recommended approach to implementing IDisposable is to have a protected Dispose(bool) method where you take action.实现 IDisposable的推荐方法是使用受保护的 Dispose(bool) 方法来执行操作。 The reason is, you want to distinguish between an explicit disposal and a disposal caused by finalization (garbage collection.)原因是,您要区分显式处置和由终结(垃圾收集)引起的处置。

When you are being disposed because of an explicit Dispose() call, it's ok to touch managed objects and you are expected to dispose of anything you've created that also needs disposing.当您因为显式的 Dispose() 调用而被处理时,可以触摸托管对象,并且您应该处理您创建的也需要处理的任何内容。 So you do this only when disposing=true.所以你只有在 disposing=true 时才这样做。

But if someone (you) forgets to call Dispose and the finalizer is called, you're being disposed after garbage collection (disposing=false) and you don't want to touch any managed objects because they may already be finalized.但是,如果有人(您)忘记调用 Dispose 并且调用了终结器,那么您将在垃圾回收之后被处理 (disposing=false),并且您不想接触任何托管对象,因为它们可能已经被终结了。 The only thing you need to free up in this case is unmanaged resources like Win32 handles and such.在这种情况下,您唯一需要释放的是非托管资源,例如 Win32 句柄等。

Finally, when Dispose() is explicitly called you'll notice I called GC.SupressFinalize(this) which is a performance hint for the garbage collector.最后,当显式调用 Dispose() 时,您会注意到我调用了 GC.SupressFinalize(this),这是垃圾收集器的性能提示。 It lets it know that the object doesn't need to be finalized when it is collected.它让它知道对象在被收集时不需要被终结。 Finalization isn't cheap.定稿并不便宜。

class MyObject : IDisposable {

    ~MyObject() {
        Dispose(false);
    }

    public void Dispose() {
        Dispose(true);
        GC.SupressFinalize(this);
    }

    protected virtual void Dispose(bool disposing) {
        if (disposing) {
            // dispose of managed resources
        }
        // dispose of unmanaged resources
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM