【问题标题】:private void Dispose(bool)?私人无效处置(布尔)?
【发布时间】:2015-08-26 23:44:51
【问题描述】:

在几个地方,人们建议使用private void Dispose(bool) 来表示IDisposable 模式。不过,这似乎已经过时了(至少对于未密封的类而言),因为新建议的模式(根据 Microsoft)是 protected virtual void Dispose(bool)

问题是,代码分析不会报告 private void Dispose(bool) 违反 CA1063,即使它似乎直接违反了模式。

这是怎么回事? private void Dispose(bool) 是否以某种方式被调用(或编译为类似于 protected virtual Dispose(bool) 的东西?

如果这是代码分析的一些问题并且是不正确的模式,有没有办法检测到这一点?可能与 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() 来解决这个问题。然后在调用A b = new B(); b.Dispose(); 时调用B b = new B(); b.dispose(); except 时,这与正确的处理模式“相似”,它只调用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 的回答,因为相对于我的问题,它基本上可以归结为“可能是一个错误”,以及一些应该作为评论的内容。如果其他人有更确凿的结论,我认为这将是一个更合适的答案。

【问题讨论】:

  • 密封类呢? protected 应该用于公开类,private 用于密封。
  • 它适用于任何一个问题。我们发现了几个未密封类没有引发问题的地方。不过,这是有道理的,密封类需要私有。尽管如此,如果类未密封(它也应该知道这一点),那么 CA 抛出它会很好。我认为我的编辑说明了为什么它可能不会完全摆脱困境,但它仍然有点烦人。
  • 调用base.Dispose() 显然违反了这种模式,所以我认为它不能解释它。我同意您最初的想法,即代码分析应该报告您提出的案例。
  • 我会完全使用another pattern
  • 这篇文章有很多问题。哪个是基本问题:为什么推荐模式发生了变化,或者为什么代码分析没有抱怨?

标签: c# code-analysis idisposable fxcop


【解决方案1】:

Implementing a Dispose Method

IDisposable 接口需要实现一个单 无参数方法,Dispose。 然而dispose 模式需要 两个 Dispose 方法来实现:

  • 没有参数的公共非虚拟(Visual Basic 中为 NonInheritable)IDisposable.Dispose 实现。
  • 受保护的虚拟(在 Visual Basic 中可重写)Dispose 方法。

由于 public、非虚拟(Visual Basic 中为 NonInheritable)、无参数 Dispose 方法由该类型的使用者调用,其目的是释放非托管资源并指示终结器(如果存在)不必运行。因此,它有一个标准实现:

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

在第二个重载中,disposing 参数是一个布尔值,指示方法调用是来自 Dispose 方法(其值为 true)还是来自终结器(其值为 false)

当垃圾收集器决定不再需要你的对象时,它会尝试完成它以防你忘记调用无参数的 dispose 方法,因为如果你这样做了并且你遵循了模式,调用将被抑制.

见:How Finalization Works

私有与受保护的虚拟:

如果您想支持正确遵循该模式的子类,则应始终使用受保护的虚拟,如文档所述。

为什么有些人使用私人版?也许是因为继承从来都不是他们的意图,特别是如果您只是使用 Resharper 等工具动态生成方法,大多数时候这些方法将是私有的。

为什么代码分析没有报告问题?

可能是一个错误。提供一个给出问题的小样本,以便其他人可以在他们的机器上进行测试。

【讨论】:

  • 当bool为真假时Dispose(bool)应该做什么不同?
  • 在页面末尾(msdn.microsoft.com/en-us/library/system.object.finalize.aspx) 你会看到一个例子,如果为真,你必须释放所有资源,因为你调用了 dispose 方法并且想要返回所有使用的内存。如果为 false,则表示垃圾收集器正在删除对象,那么您只需要处理非托管资源(在 C# 应用程序之外创建的对象),其余对象可以保持不变,因为垃圾收集器将删除需要时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-25
  • 1970-01-01
  • 1970-01-01
  • 2016-05-11
  • 1970-01-01
相关资源
最近更新 更多