C#中具有IDisposable的模板方法模式

时间:2017-10-27 13:49:15

标签: c# .net design-patterns dry idisposable

我看到在C#中实现一次性模式的common guideline是一个抽象基类,它从 IDisposable 接口实现 Dispose()方法并提供受保护的虚拟 Disposable(bool)方法。然后子类需要覆盖 Disposable(bool)并始终执行以下操作:

if (!disposed && disposing)
{
    // dispose resources here

    disposed = true;
}

我的问题是:重用这种模式是不可能的?我不喜欢在每个子类中管理这个“处置状态”。我们可以有一些这样的抽象基类:

public abstract class AbstractResource : IDisposable
{
    private bool myDisposed = false;

    protected abstract void ReleaseUnmanagedResources();

    protected virtual void ReleaseManagedResources()
    {
        // optionally override this to explicitly call Dispose() of other IDisposable objects
    }

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

    private void Dispose(bool disposing)
    {
        if (!myDisposed)
        {
            if (disposing)
            {
                ReleaseManagedResources();
            }

            ReleaseUnmanagedResources();

            myDisposed = true;
        }
    }

    ~AbstractResource()
    {
        Dispose(false);
    }
}

然后,此类用户只需要实现 ReleaseUnmanagedResources 和(可选) ReleaseManagedResources 。无需处理布尔值。

我发现this article提出了类似的技巧。但就是这样!没人提到它。这种方法有缺陷吗?

2 个答案:

答案 0 :(得分:4)

这种方法的最大缺陷是它占用了有限的资源......从一个类派生的能力意味着如果我使用你的实现,我基本上可以亲吻OOP再见,因为我需要从中派生出许多类你的类,如果我实现了接口,就无法从其他类派生它们。

所以在现实世界中,你会使用你的基类混合使用一些类,有些基于业务目的滚动它们自己的基类已经包含了IDisposable,有些只是实现了接口。我不能代表所有人,但我宁愿使用工具(例如R#)将相同的构造应用于所有类,而不是混合使用。

如果我们有能力从多个基类派生,那可能是一件事,但我们不在C#中。

答案 1 :(得分:3)

这比你想象的要糟糕。如果你有这样的类heirarchy,你可能需要检查每个方法和属性中的disposed,因为类对象可以在非托管资源的生命周期中存活很长时间,以确保你永远不会访问已处置的资源。这意味着你的抽象类实际上没有多大帮助。

它没有您想象的那么糟糕。您可能不应该首先实现终结器(~AbstractResource())或完整的Dispose模式。

通常认为课程需要这些,实际上根本不应该有这些课程。仅仅因为你在一个类中使用了非托管资源,它并不一定意味着类需要IDisposable,如果你以一种自己的类型处理它的方式使用资源。仅仅因为你实现IDisposable并不意味着你需要一个终结器,如果由IDisposable控制的资源已经被另一种类型完成了。

这篇文章也值得你花时间:

  

IDisposable: What Your Mother Never Told You About Resource Deallocation