【问题标题】:Properly disposing an object hierarchy in C#在 C# 中正确处理对象层次结构
【发布时间】:2012-10-10 20:17:09
【问题描述】:

我正在从事某个类层次结构实现 IDisposable 的项目。

一些类还实现了一个 Finalize 方法(~MyClass())

一般看起来像这样:

public class BaseClass : IDisposable
{
}

public class SomeClass : BaseClass
{
    ~SomeClass()
    {
        Dispose();
    }

    Dispose()
    {
        // Do some stuff.
        base.Dispose();
    }
}

public class AnoterClass : SomeClass
{
    ~AnoterClass()
    {
        Dispose();
    }

    Dispose()
    {
        // Do some stuff.
        base.Dispose();
    }
}

我想知道处理对 Dispose 的调用的正确方法是什么,因为似乎这些对象是通过调用 Dispose() 来处理的,然后由于调用了 Finalize 方法而导致崩溃。

最好在层次结构中的最低类保留一个标志(已处理受保护的布尔值),并在类层次结构的每个级别中检查它?

我发现每个可能的解决方案都需要一些代码重复,这不是我想要的。

【问题讨论】:

  • 包含非托管资源的复杂层次结构看起来很奇怪。您可能应该将非托管资源保存在简单的 SafeHandles 中,并避免在复杂的对象图中使用终结器。

标签: c# .net dispose idisposable finalize


【解决方案1】:

如果您的基类实现了standard IDisposable pattern,您只需将Dispose(bool disposing) 覆盖添加到本身拥有IDisposable 或非托管资源的每个派生类:

protected override void Dispose(bool disposing)
{
    try
    {
        if (disposing)
        {
            // Release managed resources
        }
        // Release unmanaged resources
    }
    finally
    {
        base.Dispose(disposing);
    }
}

您不应在任何派生类中实现终结器。

当然,层次结构中没有自己的IDisposable 资源的任何类都不需要此覆盖。

【讨论】:

  • +1 以获得更清晰的描述和我想说的示例!
  • 除非类的全部目的围绕非托管资源,否则在其层次结构中的任何类中可能不应该有终结器。相反,任何需要基于终结的清理的资源都应该封装在其自己的对象中,其目的围绕该资源。如果一个对象的终结器没有被抑制,它将导致它持有直接或间接强引用的每个对象在另一个 GC 循环中保持活动状态。因此,可终结对象应避免持有对清理不需要的外部对象的引用。
【解决方案2】:

如果您手动处理对象,则需要禁止完成。

要遵循的模式是here

编辑:

我认为你只需要在类层次结构的特定级别上实现,如果你有新的东西要在那个层次上处理,否则我相信基类中的处理会做你需要的一切。如果您在任何特定类中的实现只调用base.Dispose(disposing),那么就不需要它,如果它必须做一些干净的uop,然后调用base.Dispose(),那么您需要它。

按照您的建议使用受保护的标志应该没问题。

【讨论】:

  • 谢谢。我熟悉这种模式,问题是——它应该在类层次结构的所有级别上实现吗?没有更简单的选择吗?
  • 您应该使用您实际使用的模式更新您的示例,因为您遇到崩溃的原因是因为您没有正确实现该模式,并且没有抑制垃圾收集器调用 finalize手动处理后的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-27
  • 2011-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多