私有的void Dispose(bool)是什么意思?

5
在一些地方,有人建议在IDisposable模式中使用private void Dispose(bool)。但是这似乎已经过时了(至少对于未密封的类),因为最新的建议模式(根据微软)是protected virtual void Dispose(bool)
问题是,代码分析并没有报告private void Dispose(bool)违反了CA1063,即使它似乎直接违反了该模式。
这是怎么回事?private void Dispose(bool)是否以某种方式被调用(或编译为类似于protected virtual Dispose(bool)的内容)?
如果这是Code Analysis的问题,并且是不正确的模式,那么是否有方法来检测这个问题?也许可以使用StyleCop?
编辑:经过考虑,是因为基类可以调用base.Dispose(),从而触发private void Dispose(bool)吗?即使无法传递参数?
编辑:示例
public class A : IDisposable
{
    ~A()
    {
        this.Dispose(false);
    }

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

    private void Dispose(bool disposing) // Should be protected virtual void Dispose(bool)
    {
        Console.WriteLine("A");
    }
}

public class B : A
{
    protected virtual void Dispose(bool disposing) // Proper pattern.
    {
        Console.WriteLine("B");
    }
}

public static class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        a.Dispose(); // Prints "A"

        B b = new B();
        b.Dispose(); // Prints "A"!
    }
}

如您所见,这使得使用dispose模式非常不方便。

您可以通过隐藏public void Dispose(void)并在某处调用base.Dispose()来解决这个问题。这时候,当调用B b = new B(); b.dispose();时,它会“类似”于正确的dispose模式。但是,当调用A b = new B(); b.Dispose();时,只会调用ADispose方法。

public class B : A
{
    public void Dispose() // Causes CA error with or without "new".
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing) // Proper pattern.
    {
        base.Dispose(); // Writes "A" (without quotes).
        Console.WriteLine("B");
    }
}

基本上,整个事情看起来很糟糕。我们知道CA是否接受private void Dispose(bool),是否有一种方法可以至少通过StyleCop发出警告?

编辑:我不认为我应该接受Alexandre的答案,因为相对于我的问题,它基本上归结为“可能是一个bug”,以及应该是一个注释。如果其他人有更具决定性的东西,我认为那将是一个更合适的答案。


调用 base.Dispose() 将是模式的明显违反,因此我认为这并不能解释它。我同意你最初的想法,即代码分析应该报告你提出的情况。 - sstan
我会完全使用另一种模式 - Jordão
对我来说,问题是“为什么代码分析没有抱怨?有没有办法让某些东西(例如代码分析或Style Cop)抱怨?” - Nate Diamond
@Nate:确实不行,这就是为什么我把它作为注释添加的原因。 - Jordão
@Jordão 好的,说得好!在重新阅读我写的内容后,我觉得自己听起来比我想象中的更严厉了。这仍然是一个对未来阅读此类文章的人们有用的资源。 - Nate Diamond
显示剩余4条评论
1个回答

6

实现 Dispose 方法

The IDisposable interface requires the implementation of a single parameterless method, Dispose. However, the dispose pattern requires two Dispose methods to be implemented:

  • A public non-virtual (NonInheritable in Visual Basic) IDisposable.Dispose implementation that has no parameters.
  • A protected virtual (Overridable in Visual Basic) Dispose method.

Because the public, non-virtual (NonInheritable in Visual Basic), parameterless Dispose method is called by a consumer of the type, its purpose is to free unmanaged resources and to indicate that the finalizer, if one is present, doesn't have to run. Because of this, it has a standard implementation:

public void Dispose()
{
   // Dispose of unmanaged resources.
   Dispose (true);
   // Suppress finalization.
   GC.SuppressFinalize (this);
}

In the second overload, the disposing parameter is a Boolean that indicates whether the method call comes from a Dispose method (its value is true) or from a finalizer (its value is false).

当垃圾收集器决定您的对象不再需要时,它将尝试在您忘记调用无参dispose方法的情况下对其进行终结,因为如果您这样做并且遵循该模式,则调用将被抑制。
参见:终结工作原理 私有与受保护的虚拟:
根据文档,如果您想要支持正确遵循该模式的子类,您应始终使用受保护的虚拟。
为什么有些人使用私有版本?也许是因为继承从未是他们的意图,特别是如果您只是使用Resharper等工具动态生成方法,大多数情况下这些方法将是私有的。
为什么代码分析没有报告问题?
可能是一个bug。提供一个小样本以产生问题,以便其他人可以在他们的机器上测试。

当Dispose(bool)的bool值为true和false时应该有什么不同的处理? - AksharRoop
在页面的末尾(https://msdn.microsoft.com/en-us/library/system.object.finalize.aspx),您将看到一个示例。如果为 true,则必须处理所有资源,因为您调用了 dispose 方法并希望回收所有已使用的内存。如果为 false,则表示垃圾回收器正在删除该对象,然后您只需要处理非托管资源(即创建在 C# 应用程序之外的对象),其余对象可以保持不变,因为当垃圾回收器需要时将删除它们。 - Alexandre Borela

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