在 C# 中使用 IDisposable 的模板方法模式
Template method pattern with IDisposable in C#
我看到 common guideline 在 C# 中实现一次性模式是有一个抽象基础 class 实现 Dispose() 方法IDisposable 接口并提供受保护的虚拟 Disposable(bool) 方法。然后 sub-classes 需要覆盖 Disposable(bool) 并且总是做类似的事情:
if (!disposed && disposing)
{
// dispose resources here
disposed = true;
}
我的问题是:不可能重用这个模式吗?我不喜欢必须在每个子 class 中管理这个 "disposed state"。我们可以有一些像这样的抽象基础 class:
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);
}
}
然后这个 class 的用户只需要实现 ReleaseUnmanagedResources 和(可选)ReleaseManagedResources。无需处理布尔值。
我发现 this article 提出了类似的技术。但就是这样!没有其他人提到它。这种方法有缺陷吗?
这种方法的最大缺陷是它占用了有限的资源...从一个资源派生的能力 class 意味着如果我使用你的实现,我基本上可以和 OOP 说再见了,因为我会需要从您的 class 中派生出许多 class 并且不能从另一个 class 中派生出它们,如果我实现了接口就可以。
所以在现实世界中,您会混合使用您的 baseclass 一些 classes,一些出于商业目的滚动他们自己的 baseclass包含 IDisposable
和一些只是实现接口。我不能代表所有人,但我宁愿使用工具(例如 R#)将 same 构造应用于所有 classes,而不是将事物混合在一起.
如果我们有能力从多个基础派生 class,这可能是一回事,但我们在 C# 中没有。
比你想象的还要糟糕。如果你有这样的 class 层次结构,你可能需要检查 每个方法中的 disposed
和 属性,因为 class对象可以在非托管资源的生命周期之后存活很长时间,以确保您永远不会访问已处置的资源。这意味着你的摘要 class 真的没有太大帮助。
没有你想的那么糟糕。您可能一开始就不应该实现终结器 (~AbstractResource()
) 或完整的 Dispose 模式。
人们普遍认为 class他们需要这些实际上根本不应该拥有的东西。仅仅因为您在 class 中使用了非托管资源,这并不一定意味着 class 需要 IDisposable
,如果您以按其自身类型处理资源的方式使用该资源。如果 IDisposable
控制的资源已经被另一种类型终结,那么仅仅因为你实现了 IDisposable
并不意味着你需要终结器。
这篇文章也值得您阅读:
IDisposable: What Your Mother Never Told You About Resource Deallocation
我看到 common guideline 在 C# 中实现一次性模式是有一个抽象基础 class 实现 Dispose() 方法IDisposable 接口并提供受保护的虚拟 Disposable(bool) 方法。然后 sub-classes 需要覆盖 Disposable(bool) 并且总是做类似的事情:
if (!disposed && disposing)
{
// dispose resources here
disposed = true;
}
我的问题是:不可能重用这个模式吗?我不喜欢必须在每个子 class 中管理这个 "disposed state"。我们可以有一些像这样的抽象基础 class:
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);
}
}
然后这个 class 的用户只需要实现 ReleaseUnmanagedResources 和(可选)ReleaseManagedResources。无需处理布尔值。
我发现 this article 提出了类似的技术。但就是这样!没有其他人提到它。这种方法有缺陷吗?
这种方法的最大缺陷是它占用了有限的资源...从一个资源派生的能力 class 意味着如果我使用你的实现,我基本上可以和 OOP 说再见了,因为我会需要从您的 class 中派生出许多 class 并且不能从另一个 class 中派生出它们,如果我实现了接口就可以。
所以在现实世界中,您会混合使用您的 baseclass 一些 classes,一些出于商业目的滚动他们自己的 baseclass包含 IDisposable
和一些只是实现接口。我不能代表所有人,但我宁愿使用工具(例如 R#)将 same 构造应用于所有 classes,而不是将事物混合在一起.
如果我们有能力从多个基础派生 class,这可能是一回事,但我们在 C# 中没有。
比你想象的还要糟糕。如果你有这样的 class 层次结构,你可能需要检查 每个方法中的 disposed
和 属性,因为 class对象可以在非托管资源的生命周期之后存活很长时间,以确保您永远不会访问已处置的资源。这意味着你的摘要 class 真的没有太大帮助。
没有你想的那么糟糕。您可能一开始就不应该实现终结器 (~AbstractResource()
) 或完整的 Dispose 模式。
人们普遍认为 class他们需要这些实际上根本不应该拥有的东西。仅仅因为您在 class 中使用了非托管资源,这并不一定意味着 class 需要 IDisposable
,如果您以按其自身类型处理资源的方式使用该资源。如果 IDisposable
控制的资源已经被另一种类型终结,那么仅仅因为你实现了 IDisposable
并不意味着你需要终结器。
这篇文章也值得您阅读:
IDisposable: What Your Mother Never Told You About Resource Deallocation