简体   繁体   English

C#如何实现Dispose方法

[英]C# how to implement Dispose method

I need some advice on the implementation of the Dispose method. 我需要一些关于Dispose方法实现的建议。

In our application the user designs their own UI. 在我们的应用程序中,用户设计自己的UI。 I have a preview window that shows what the UI is going to look like. 我有一个预览窗口,显示UI的外观。 All object drawn in this UI ultimately derive from a common base class ScreenObject. 在此UI中绘制的所有对象最终都来自公共基类ScreenObject。 My preview manager contain a single object reference to a ScreenGrid which is the grid object for the entire preview area. 我的预览管理器包含对ScreenGrid的单个对象引用,ScreenGrid是整个预览区域的网格对象。

Question #1 问题#1

Some of my derived screen classes hold onto unmanaged resources, such as a database connection, bitmap image and a WebBrowser control. 我的一些派生屏幕类保留在非托管资源上,例如数据库连接,位图图像和WebBrowser控件。 These classes need to dispose of these objects. 这些类需要处理这些对象。 I created a virtual Dispose method in the base ScreenObject base class and then implemented an override Dispose method in each of the derived classes that hold onto unmanaged resources. 我在基本ScreenObject基类中创建了一个虚拟Dispose方法,然后在每个保存到非托管资源的派生类中实现了一个覆盖Dispose方法。 However, right now I just created a method called Dispose , I am not implementing IDisposable . 但是,现在我刚刚创建了一个名为Dispose的方法,我没有实现IDisposable Should I implement IDisposable ? 我应该实现IDisposable吗? If so how do I implement it? 如果是这样,我该如何实现它?

  • Just on the derived classes that have unmanaged resources 只是在具有非托管资源的派生类上
  • The base class and derived classes that have unmanaged resources OR 基类和具有非托管资源派生类
  • The base class and all derived classes including those that do not have unmanaged resources 基类和所有派生类,包括那些没有非托管资源的类

Is it wrong to put a virtual Dispose method in a base class that doesn't have unmanaged resources so that you can take advantage of polymorphism? 将虚拟Dispose方法放在没有非托管资源的基类中是否错误,以便您可以利用多态?

Question #2 问题2

In reading about the Dispose method and the IDisposable interface Microsoft states that the disposing object should only call the Dispose method for its parent. 在阅读Dispose方法和IDisposable接口时,Microsoft声明处置对象应该只为其父级调用Dispose方法。 The parent will call it for its parent and so on. 父母将为其父母调用它,依此类推。 To me this seems backwards. 对我而言,这似乎是倒退。 I may want to dispose of a child but keep its parent around. 我可能想要处理一个孩子但保留其父母。

I would think it should be the other way around, an object being disposed should dispose of its children. 我认为它应该是另一种方式,处置的对象应该处理它的孩子。 The children should then dispose of their children and so on. 然后孩子们应该处理他们的孩子等等。

Am I wrong here or am I missing something? 我错在这里还是我错过了什么?

Question 1: Implement IDisposable as well, using the following pattern: 问题1:使用以下模式实现IDisposable

public class MyClass : IDisposable
{
    bool disposed;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                //dispose managed resources
            }
        }
        //dispose unmanaged resources
        disposed = true;
    }

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

Question 2: What Microsoft means is that a derived class calls dispose on it's parent class. 问题2:Microsoft的含义是派生类在其父类上调用dispose。 The owner of the instance only calls Dispose on the most derived type. 实例的所有者仅在最派生类型上调用Dispose。

An (shortened) example: 一个(缩短的)例子:

class Parent : IDisposable 
{
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                //dispose managed resources
            }
        }
        //dispose unmanaged resources
        disposed = true;
    }

}
class Child : Parent, IDisposable 
{ 
    protected override void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                //dispose managed resources
            }
            base.Dispose(disposing);
        }
        //dispose unmanaged resources
        disposed = true;
    }

}
class Owner:IDisposable
{
    Child child = new Child();
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                if(child!=null)
                {
                    child.Dispose();
                }
            }
        }
        //dispose unmanaged ressources
        disposed = true;
    }
}

The owner only calls Dispose on the Child, but not on the Parent. 所有者只调用Child上的Dispose ,但不调用Parent。 The Child is responsible for calling Dispose on the Parent. Child负责在Parent上调用Dispose

Question 1: 问题1:

Based on the types of objects that you list (ie Database, WebBrowser, Bitmap, etc.) these are only managed resources as far as .NET is concerned. 根据您列出的对象类型(即数据库,WebBrowser,位图等),就.NET而言,这些只是受资源。 Thus, you should implement IDisposable on any class that has disposable types as members. 因此,您应该在具有一次性类型作为成员的任何类上实现IDisposable If they are locally declared instances, you just call 'using()' on them. 如果它们是本地声明的实例,则只需对它们调用'using()'。 While these instances you mention do have unmanaged resources under them, this is abstracted away from you by .NET thru the types you are using. 虽然你提到的这些实例确实有非托管资源,但是这些实际上是通过.NET从你使用的类型中抽象出来的。 Since you are only using managed types, you should implement IDisposable but without a finalizer . 由于您只使用托管类型,因此您应该实现IDisposable 但不使用终结器 You only need to implement a finalizer if you truly have unmanaged resources as class members. 如果您真的拥有非托管资源作为类成员,则只需要实现终结器。

Question 2: 问题2:

It seems that you are confusing inheritance (is a) with aggregation/containment (has a). 看来你将继承(是a)与聚合/包含混淆(有一个)。 For example, if "Container" contains a disposable resource as a class member, it is called aggregation/containment. 例如,如果“Container”包含一次性资源作为类成员,则称为聚合/包含。 So, calling base.Dispose() in the IDisposable implementation of Container has nothing to do with disposing of the disposable resource inside of Container. 因此,在Container的IDisposable实现中调用base.Dispose()与在Container 内部处理一次性资源无关。 You should remember that if a class derives from Container, say "DerivedContainer", that it is an instance of Container albeit with additional members and/or functionality. 您应该记住,如果一个类派生自Container,比如说“DerivedContainer”,那么它 Container的一个实例,尽管有其他成员和/或功能。 So any instance of "DerivedContainer" has all of the members that its base class "Container" does. 因此,“DerivedContainer”的任何实例都具有其基类“Container”所具有的所有成员。 If you never called base.Dispose() , the disposable resource in "Container" would not be released properly (it would actually by the GC, but it's bad practice for many reasons to just 'let .NET take care of it') - please refer to my posted answer at Is it bad practice to depend on the .NET automated garbage collector? 如果你从未调用过base.Dispose() ,那么“容器”中的可支配资源将无法正常释放(它实际上是由GC实现的,但是由于很多原因,只是'让.NET处理它'是不好的做法) -请参阅我发布的答案, 依赖.NET自动垃圾收集器是不好的做法? .

If you didn't call the base class Dispose() , you'd end up with a partially disposed object (disposed in the derived class but not in the base class) - a very bad scenario. 如果你没有调用基类Dispose() ,你最终会得到一个部分处理的对象(放置在派生类中但不在基类中) - 这是一个非常糟糕的场景。 So it is very important to call the base class Dispose() . 因此调用基类Dispose()非常重要。

I have a best practices pattern I've developed (with lots of experience and debugging memory dumps) written on my blog as an example. 作为一个例子,我在我的博客上写了一个我已经开发的最佳实践模式(有很多经验和调试内存转储)。 It shows how to implement IDisposable on a base class as well as a derived class: 它展示了如何在基类和派生类上实现IDisposable

http://dave-black.blogspot.com/2011/03/how-do-you-properly-implement.html http://dave-black.blogspot.com/2011/03/how-do-you-properly-implement.html

I Implement IDisposable 我实现了IDisposable

 class ConnectionConfiguration:IDisposable
{
    private static volatile IConnection _rbMqconnection;
    private static readonly object ConnectionLock = new object();
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!disposing)
        {
            return;
        }
        if (_rbMqconnection == null)
        {
            return;
        }
        lock (ConnectionLock)
        {
            if (_rbMqconnection == null)
            {
                return;
            }
            _rbMqconnection?.Dispose();//double check
            _rbMqconnection = null;
        }
    }
}

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

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