c# - 为什么正确实现 IDisposable 的方案很复杂?

标签 c# idisposable finalizer

今天早些时候我遇到了 CA1063在工作中对某些代码运行代码分析时。

我有两个问题:

  1. 为什么以下代码即使明显违反了某些要求(例如 Dispose 被覆盖)也不会导致 CA1063

  2. 导致具有由密封 Dispose() 和 Finalizer 等调用的虚拟 Dispose(bool) 的复杂方案的代码的实际问题是什么....

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
  class Foobar : IDisposable
  {
    public Foobar()
    {
      Console.Out.WriteLine("Constructor of Foobar");
    }

    public virtual void Dispose()
    {
      Console.Out.WriteLine("Dispose of Foobar");
      GC.SuppressFinalize(this);
    }

    ~Foobar()
    {
      Console.Out.WriteLine("Finalizer of Foobar");
    }
  }

  class Derived : Foobar
  {
    public Derived()
    {
      Console.Out.WriteLine("Constructor of Derived");
    }

    public override void Dispose()
    {
      Console.Out.WriteLine("Dispose of Derived");
      GC.SuppressFinalize(this);
      base.Dispose();
    }

    ~Derived()
    {
      Console.Out.WriteLine("Finalizer of Derived");
    }
  }

  class Program
  {
    static void Main()
    {
      Console.Out.WriteLine("Start");
      using (var foo = new Derived())
      {
        Console.Out.WriteLine("...");
      }
      Console.Out.WriteLine("End");
    }
  }
}

最佳答案

最初,Microsoft 期望许多类型的对象将封装托管和非托管资源,并且即使特定的可继承类没有封装任何非托管资源,从它派生的类也可能封装。尽管这种想法在很大程度上是错误的(将非托管资源隔离到它们自己的对象中通常要好得多,然后这些对象可以用作托管资源),旨在处理任意混合的托管和非托管资源的模式成为了一个既定的先例.

即使完整 Dispose 模式的某些部分很愚蠢,适当的简化也不会遗漏很多。清理代码应该在 protected 虚方法中,以便允许派生类添加自己的逻辑但仍链接到父类方法;如果该方法的名称为 Dispose,则它的签名必须与无参数 Dispose 方法的签名不同 [尽管我自己的偏好是名称不同的无参数方法].我对微软模式最大的提示是它要求每个派生类都有自己的逻辑来防止重复处理;让基类在非虚拟 Dispose 实现中处理它会更干净。

关于c# - 为什么正确实现 IDisposable 的方案很复杂?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15346952/

相关文章:

c# - 哪个Lucene SearchAnalyzer用于特殊字符搜索

c# - 如何在 C# 中通过字符串调用构造函数(即通过反射)?

c# - 我将如何在这种情况下实现 IDisposable?

c# - 处理实现 IDisposable 的成员

c# - StreamWriter 什么时候被释放?

c# - 对非托管资源进行 P/Invoke 时,何时需要 GC.KeepAlive(this)?

c# - iTextSharp 中 HTMLWorker 的 Stack Empty 异常

c# - 我可以实现一个泛型类型并向它传递一个仅在运行时才知道的类型吗?

c# - NUnit 不会因终结器中的异常而失败

java - SWIG 结构成员被 Java 的垃圾收集器过早释放