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

3

我有一个类实现了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();
        }
    }
}

这在代码分析中没有引起任何警告(我从MSDN获取了代码,作为如何正确完成的示例)。

由于我只打算声明一个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();
        }
    }
}

代码警告说,dispose方法应该是new的,因为它们隐藏了成员,我做到了,但我还得到了以下警告:

"Warning CA1063 Ensure that 'AsyncSerial.Dispose()' is declared as public and sealed"

将其标记为sealed意味着它必须被标记为override(否则我会得到编译器错误),将其标记为override意味着它可以是new,所以我最终得到了:

Error CS0506 'AsyncSerial.Dispose()': cannot override inherited member 'Component.Dispose()' because it is not marked virtual, abstract, or override

我不知道在具有父类IDisposable的类上实现disposing的“正确”方法。我找到的每个示例都只适用于将IDisposable作为基础,但使我的类

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

当我试图让 SerialPort 实现 IDisposable 接口时,代码分析器给出了警告。

我应该只是忽略有关确保 'AsyncSerial.Dispose()' 声明为 public 和 sealed 的警告,还是有一种正确的方法可以避免这种代码分析警告。


1
嵌入式SerialPort很好,但你只需要在Dispose()方法中处理它,不需要使用一次性模式。 使用sealed毫不犹豫。继承也是可以的,但是你只需要重写Dispose(bool)并且不需要继承IDisposable。既然似乎没有其他可处理的可一次性对象,这样做就没必要了。 - Hans Passant
3个回答

8

如果有什么需要的话,你的子类应该重写Dispose(bool disposing)方法,这是这个方法存在的全部意义。

但是,我猜基类会自动调用正确的方法,所以除非你有额外的需要释放的资源没有在Close()中被释放,否则你不需要做任何操作。如果有这种情况,请在Dispose(bool disposing)中完成释放:

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

请注意,您当前的实现会导致 StackOverflowException 异常,因为您的两个 Dispose 重载相互调用。

好的,我会确保我处理掉子类中创建的任何东西(尽管我不认为有什么)。基类处理其他所有内容,我过于复杂化了它并且让自己感到困惑。谢谢。 - MikeS159

1
Dispose模式旨在允许派生类型以一致的方式添加处理逻辑,而不必考虑父类型是否具有公共Dispose方法或显式实现IDisposable.Dispose。从遵循该模式的类型派生的类型应仅覆盖Dispose(bool),而不管父类如何使用公共方法或显式实现IDisposable.Dispose()。
尽管Dispose模式的设计基于这样一个错误的假设:可继承类型的公开对象通常需要直接包含终结器(而不是将非托管资源封装在私有类型的私有实例中,其目的是清理这些资源),但C++/CLI(和可能也有其他语言)中编译器生成的清理逻辑依赖于该模式,因此对于可能被他人使用的可继承类使用它是个好主意。

0

你不需要在子类中声明一个public void Dispose()方法,因为它已经从基类继承了(除非你使用new关键字隐藏了基类的实现,否则编译器是不允许的)。

如果你不打算释放任何特定于这个子类的东西,也不需要覆盖基类的protected virtual void Dispose(bool)方法。

如果你在子类中有一个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);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接