【问题标题】:Template method pattern with IDisposable in C#C# 中带有 IDisposable 的模板方法模式
【发布时间】:2018-04-09 03:41:48
【问题描述】:

我看到 common guideline 在 C# 中实现一次性模式是有一个抽象基类,它从 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 提出了类似的技术。但就是这样!没有其他人提到它。这种方法有缺陷吗?

【问题讨论】:

  • 是的,这是完全有效的。这里的重点是;您真正需要使用终结器来实现完整的IDisposable 模式的时候,实际上从来没有。仅当您需要处理原始资源时才需要这样做,并且其中大多数已经在框架中的某处实现了 IDisposable 包装器,因此您一开始就不需要这样做。
  • 您的抽象类是否处理非托管资源?

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


【解决方案1】:

这种方法的最大缺陷是它占用了有限的资源......从一个类派生的能力意味着如果我使用你的实现,我基本上可以告别 OOP,因为我需要从如果我实现了接口,则无法从另一个类派生它们。

因此,在现实世界中,您将有一些使用您的基类的类的狂野组合,一些为业务目的滚动他们自己的基类,这些基类已经包含了IDisposable,还有一些只是实现了接口。我不能代表所有人,但我宁愿使用工具(例如 R#)将 same 构造应用于所有类,而不是乱七八糟地混合使用。

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

【讨论】:

    【解决方案2】:

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

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

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

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

    IDisposable: What Your Mother Never Told You About Resource Deallocation

    【讨论】:

    • 关于“确保您永远不会访问已处置的资源”,这是您在任何实现 IDisposable 的类中都需要关注的问题,不是吗?不仅是我的抽象基类。顺便说一句,感谢您的文章!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-06
    • 2011-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多