简体   繁体   English

在C#中的父类上正确实现IDisposable

[英]Implementing IDisposable correctly on parent classes in C#

I have a class which implements the C# SerialPort which used to look like this: 我有一个实现C# SerialPort的类,它常常如下所示:

public class AsyncSerial : IDisposable
{
    SerialPort newPort; //Parameters declared in my constructor
    //Constructor and other methods

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

    protected virtual void Dispose(bool disposing)
    {
        if(disposing)
        {
            this.Close();
            this.Dispose();
        }
    }
}

This throws up no warnings in code analysis (I got the code from MSDN as an example of how to do it properly). 这在代码分析中不会引发任何警告(我从MSDN获取代码作为如何正确执行此操作的示例)。

Since I was only ever going to declare one SerialPort I figured I would make my class a child of SerialPort , but now I get warnings that I can't seem to fix. 由于我只是要声明一个SerialPort我想我会让我的班级成为SerialPort的孩子,但现在我收到警告,我似乎无法修复。

public class AsyncSerial : SerialPort
{
    //Constructor and other methods

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

    protected new virtual void Dispose(bool disposing)
    {
        if(disposing)
        {
            this.Close();
            this.Dispose();
        }
    }
}

Code warnings said the dispose methods should be new as they hide members, which I did, but I also get: 代码警告说处理方法应该是new因为它们隐藏了成员,我做了,但我也得到:

"Warning CA1063 Ensure that 'AsyncSerial.Dispose()' is declared as public and sealed" “警告CA1063确保'AsyncSerial.Dispose()'被声明为公共密封”

Making it sealed means it has to be marked override (or I get compiler errors), making it override means it can be new, so I end up with: 使其密封意味着它必须被标记为override (或者我得到编译器错误),使其覆盖意味着它可以是新的,所以我最终得到:

Error CS0506 'AsyncSerial.Dispose()': cannot override inherited member 'Component.Dispose()' because it is not marked virtual, abstract, or override 错误CS0506'AsyncSerial.Dispose()':无法覆盖继承的成员'Component.Dispose()',因为它未标记为虚拟,抽象或覆盖

I don't know the 'correct' way to implement disposing on a class with IDisposable in the parent class. 我不知道在父类中使用IDisposable实现处理的“正确”方法。 Every example I find only fits having IDisposable as a base, but making my class 我找到的每个例子都只适合以IDisposable作为基础,但是我的课程

public class AsyncSerial : SerialPort, IDisposable
{
    //code
}

gives me a code analysis warning because SerialPort already implements IDisposable . 给我一个代码分析警告,因为SerialPort已经实现了IDisposable

Should I just suppress the warning about Ensuring that 'AsyncSerial.Dispose()' is declared as public and sealed, or is there a correct way to do this which doesn't give code analysis warning. 我是否应该禁止关于确保'AsyncSerial.Dispose()'被声明为公共和密封的警告,或者是否有正确的方法来执行此操作而不提供代码分析警告。

Your subclass should override Dispose(bool disposing) if anything - that's the whole point of having that method at all, really. 如果有的话,你的子类应该重写Dispose(bool disposing) - 这就是完全拥有该方法的全部意义。

However, I suspect that the base class will make the right calls anyway, so you shouldn't need to do anything, unless you have extra resources to release which aren't released in Close() . 但是,我怀疑基类无论如何都会进行正确的调用,所以你不需要做任何事情,除非你有额外的资源要释放, 而不是Close()释放。 If that's the case, do that in Dispose(bool disposing) : 如果是这种情况,请在Dispose(bool disposing)

protected override void Dispose(bool disposing)
{
    // Allow the base class to release resources
    base.Dispose(disposing);
    // Release any extra resources here 
}

Note that your current implementation will lead to a StackOverflowException as your two Dispose overloads call each other. 请注意,您的当前实现将导致StackOverflowException,因为您的两个Dispose重载相互调用。

The Dispose Pattern was designed to allow derived types to add disposal logic in consistent fashion without regard for whether the parent type has a public Dispose method or implements IDisposable.Dispose explicitly. Dispose Pattern旨在允许派生类型以一致的方式添加处理逻辑,而不考虑父类型是否具有公共Dispose方法或显式实现IDisposable.Dispose Types which derive from a type that follows the pattern should simply override Dispose(bool) regardless of how the parent class implements uses a public method or explicit implementation for IDisposable.Dispose() . 从模式后面的类型派生的类型应该简单地重写Dispose(bool)无论父类如何使用公共方法或IDisposable.Dispose()显式实现。

Although the design of the Dispose pattern was based on the flawed assumption that publicly-exposed objects of inheritable types will often need to incorporate finalizers directly (rather than encapsulating unmanaged resources in privately-held instances of private types whose purpose is to clean up those resources), compiler-generated cleanup logic in C++/CLI (and maybe other languages as well) relies upon the pattern and so it's a good idea to use it with inheritable classes which may be used by other people. 尽管Dispose模式的设计基于以下缺陷:假设公开的可继承类型对象通常需要直接合并终结器(而不是将非托管资源封装在私有类型的私有实例中,其目的是清理这些资源) ),C ++ / CLI中编译器生成的清理逻辑(也可能是其他语言)依赖于模式,因此将它与可由其他人使用的可继承类一起使用是个好主意。

You don't need to declare a public void Dispose() method on the child class, because it was already inherited from the base one (The compiler won't let you anyways, unless you hide the base implementation with the new keyword). 您不需要在子类上声明一个public void Dispose()方法,因为它已经从基类继承(编译器不会允许您,除非您使用new关键字隐藏基本实现)。

You also don't need to override the base class's protected virtual void Dispose(bool) if you're not going to dispose anything specific to this child class. 如果您不打算处理特定于此子类的任何内容,则也不需要覆盖基类的protected virtual void Dispose(bool)

If you were to have an IDisposable reference in your child class, then you should override your base class's method: 如果您的子类中有IDisposable引用,那么您应该覆盖基类的方法:

public class AsyncSerial : SerialPort, IDisposable
{
    // SomeClass implements IDisposable
    private SomeClass _disposableInstance;

    // ...

    protected override void Dispose(bool disposing)
    {
        if(disposing)
        {
            if(_disposableInstance != null)
                _disposableInstance.Dispose();
        }

        // Call the base Dispose, to release resources on the base class.
        base.Dipose(disposing);
    }
}

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

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