【问题标题】:How do you "properly" implement Dispose() (according to FxCop) when your implementation is an empty method? (CA1063)当您的实现是空方法时,您如何“正确”实现 Dispose()(根据 FxCop)? (CA1063)
【发布时间】:2012-02-15 09:47:54
【问题描述】:

我有一个接口的实现,该接口扩展了IDisposable。在我特定的接口实现中,我不需要处理任何东西,所以我只有一个空的Dispose() 方法。

public interface IMyStuff : IDisposable
{
}

public MyStuffImpl : IMyStuff
{
    public void Dispose()
    {
    }
}

现在在 FxCop 中,这会导致 CA1063:

Error, Certainty 95, for ImplementIDisposableCorrectly
{
    Resolution   : "Provide an overridable implementation of Dispose(
                   bool) on 'MyStuffImpl' or mark the type as sealed. 
                   A call to Dispose(false) should only clean up native 
                   resources. A call to Dispose(true) should clean up 
                   both managed and native resources."
}
CriticalWarning, Certainty 75, for CallGCSuppressFinalizeCorrectly
{
    Resolution   : "Change 'MyStuffImpl.Dispose()' to call 'GC.SuppressFinalize(
                   object)'. This will prevent derived types that introduce 
                   a finalizer from needing to re-implement 'IDisposable' 
                   to call it."
}
Error, Certainty 95, for ImplementIDisposableCorrectly
{
    Resolution   : "Modify 'MyStuffImpl.Dispose()' so that it 
                   calls Dispose(true), then calls GC.SuppressFinalize 
                   on the current object instance ('this' or 'Me' in Visual 
                   Basic), and then returns."
}

所以,看来我可以通过以下两种方式之一解决此问题:


创建类sealed:

public sealed MyStuffImpl : IMyStuff
{
    public void Dispose()
    {
    }
}

实现部分典型模式:

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

    private void Dispose(bool disposing)
    {
    }
}

就我而言,我不打算扩展此实现,因此我可能会通过将其设置为sealed 来解决它,但我承认我真的不明白为什么它是否密封很重要.

另外,仅仅因为我的班级是封闭的,FxCop 不再告诉我Dispose() 应该调用GC.SupressFinalize(this);,但这是真的吗?在 .NET 中总是在 Dispose 中调用 SupressFinalize 是否“更好”?

【问题讨论】:

  • 如果你的接口实现了不需要处理的接口,也许你的接口不应该实现 IDisposable。您还可以根据需要在界面中实现 IDisposable
  • @DBM OP 正在实现另一个继承 IDisposable 的接口。 IEnumerator<T> 就是一个例子。
  • @DBM:如果大多数实现都是一次性的,那么这个接口也应该是一次性的,以鼓励该接口的用户正确处理。
  • 我不知道 FxCop 在做什么,但我想指出您的课程实际上缺少终结器。所以 SuppressFinalize 什么都不做。
  • @DBM:如果工厂要返回的东西可能是IDisposable,也可能不是,那么工厂的返回类型应该是IDisposable。这就是IEnumerator<T>实现IDisposable的原因——它是工厂方法的返回类型。

标签: c# .net idisposable fxcop


【解决方案1】:

SuppressFinalize() 没有意义,除非您的实例有终结器。
如果你的类没有终结器,但不是sealed,你仍然应该SuppressFinalize,以防继承的类添加终结器。

您的两个选项都是正确的,除了 Dispose(bool) 必须是 protected virtual

【讨论】:

  • 其实第二个选项是不正确的,因为Dispose(bool)重载是不可覆盖的。 +1 指出 SuppressFinalize 在没有终结器的对象上毫无意义。
  • 在任何情况下,一个类应该将一个清理终结器添加到一个不是为基类设计的基类,并且有什么理由这样一个类无法处理其 GC.SuppressFinalize自己的 Dispose 方法?我知道类拥有终结器可能很有用,其目的只是记录处理失败,但是当基类不是为它设计时尝试在终结器中进行清理似乎是危险和错误的。封装一个可终结类的实例似乎更安全。
  • @supercat:如果派生类添加了非托管资源。派生类不能覆盖Dispose()。 (虽然我不确定为什么它不能在Dispose(true) 中调用SupressFinalize()
  • @SLaks:派生类何时应该添加非托管资源,而不是将这些资源封装在一个旨在管理它们的新类中?该新类的实例将成为托管资源,因此无需将非托管资源添加到派生类中。
【解决方案2】:

在您的“实现部分典型模式”选项中,您应该将Dispose(bool) 方法设为protected virtual

protected virtual void Dispose(bool disposing) 
{ 
} 

这将为子类提供处理他们管理的任何资源的机会。这就是“提供Dispose(bool)的可覆盖实现”中“可覆盖”的意思

当然,public virtual 也会满足 FxCop。

【讨论】:

  • @rally25rs 但是 FxCop 确实警告过你,当它说“提供 Dispose(bool) 的可覆盖实现”时。当您提供 Dispose(bool) 的不可覆盖实现时,警告是否消失了?如果是这样,那就太奇怪了。
  • 是的,在我的第二个示例中,Dispose() 是私有的,没有 FxCop 警告。
猜你喜欢
  • 2010-10-12
  • 2011-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-22
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多