问题描述
假设我有这样一组简单的类:
Let's say I have a simple set of classes like this:
class Bus
{
Driver busDriver = new Driver();
}
class Driver
{
Shoe[] shoes = { new Shoe(), new Shoe() };
}
class Shoe
{
Shoelace lace = new Shoelace();
}
class Shoelace
{
bool tied = false;
}
一个Bus
有一个Driver
,Driver
有两个Shoe
,每个Shoe
有一个 鞋带
.都非常傻.
A Bus
has a Driver
, the Driver
has two Shoe
s, each Shoe
has a Shoelace
. All very silly.
后来我决定 Shoelace
上的某些操作可以是多线程的,所以我添加了一个 EventWaitHandle
以便线程与之通信.所以 Shoelace
现在看起来像这样:
Later I decide that some operation on the Shoelace
could be multi-threaded, so I add an EventWaitHandle
for the threads to communicate with. So Shoelace
now looks like this:
class Shoelace
{
private AutoResetEvent waitHandle = new AutoResetEvent(false);
bool tied = false;
// ... other stuff ..
}
在鞋带上实现 IDisposable
但现在 微软的 FxCop 会抱怨:在鞋带"上实现 IDisposable,因为它创建以下 IDisposable 类型的成员:'EventWaitHandle'."
好的,我在 Shoelace
上实现了 IDisposable
,而我整洁的小班级变成了这个可怕的烂摊子:
Okay, I implement IDisposable
on Shoelace
and my neat little class becomes this horrible mess:
class Shoelace : IDisposable
{
private AutoResetEvent waitHandle = new AutoResetEvent(false);
bool tied = false;
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~Shoelace()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
if (waitHandle != null)
{
waitHandle.Close();
waitHandle = null;
}
}
// No unmanaged resources to release otherwise they'd go here.
}
disposed = true;
}
}
或者(正如评论者所指出的)因为 Shoelace
本身没有非托管资源,我可能会使用更简单的 dispose 实现而不需要 Dispose(bool)
和析构函数:
Or (as pointed out by commenters) since Shoelace
itself has no unmanaged resources, I might use the simpler dispose implementation without needing the Dispose(bool)
and Destructor:
class Shoelace : IDisposable
{
private AutoResetEvent waitHandle = new AutoResetEvent(false);
bool tied = false;
public void Dispose()
{
if (waitHandle != null)
{
waitHandle.Close();
waitHandle = null;
}
GC.SuppressFinalize(this);
}
}
在 IDisposable 传播时惊恐地看着
没错,就是这样.但是现在 FxCop 会抱怨 Shoe
创建了一个 Shoelace
,所以 Shoe
也必须是 IDisposable
.
Watch in horror as IDisposable spreads
Right that's that fixed. But now FxCop will complain that Shoe
creates a Shoelace
, so Shoe
must be IDisposable
too.
而Driver
创建Shoe
,所以Driver
必须是IDisposable
.而 Bus
创建 Driver
所以 Bus
必须是 IDisposable
等等.
And Driver
creates Shoe
so Driver
must be IDisposable
.
And Bus
creates Driver
so Bus
must be IDisposable
and so on.
突然间,我对 Shoelace
的小改动给我带来了很多工作,我的老板想知道为什么我需要结帐 Bus
来更改 Shoelace
.
Suddenly my small change to Shoelace
is causing me a lot of work and my boss is wondering why I need to checkout Bus
to make a change to Shoelace
.
您如何防止 IDisposable
的这种传播,但仍确保您的非托管对象得到正确处置?
How do you prevent this spread of IDisposable
, but still ensure that your unmanaged objects are properly disposed?
推荐答案
你不能真正阻止" IDisposable 传播.有些类需要被释放,例如AutoResetEvent
,最有效的方法是在Dispose()
方法中完成,以避免终结器的开销.但是这个方法必须以某种方式调用,所以就像在你的例子中一样,封装或包含 IDisposable 的类必须处理这些,所以它们也必须是一次性的,等等.避免它的唯一方法是:
You can't really "prevent" IDisposable from spreading. Some classes need to be disposed, like AutoResetEvent
, and the most efficient way is to do it in the Dispose()
method to avoid the overhead of finalizers. But this method must be called somehow, so exactly as in your example the classes that encapsulate or contain IDisposable have to dispose these, so they have to be disposable as well, etc. The only way to avoid it is to:
- 尽可能避免使用 IDisposable 类,在单个位置锁定或等待事件,将昂贵的资源保存在单个位置等
- 仅在需要时创建它们并在之后处理它们(
using
模式)
在某些情况下,可以忽略 IDisposable,因为它支持可选情况.例如,WaitHandle 实现 IDisposable 以支持命名的 Mutex.如果未使用名称,则 Dispose 方法不执行任何操作.MemoryStream 是另一个例子,它不使用系统资源,而且它的 Dispose 实现也不做任何事情.仔细考虑是否正在使用非托管资源可能具有指导意义.因此可以检查 .net 库的可用源或使用反编译器.
In some cases IDisposable can be ignored because it supports an optional case. For example, WaitHandle implements IDisposable to support a named Mutex. If a name is not being used, the Dispose method does nothing. MemoryStream is another example, it uses no system resources and its Dispose implementation also does nothing. Careful thinking about whether an unmanaged resource is being used or not can be instructional. So can examining the available sources for the .net libraries or using a decompiler.
这篇关于您如何防止 IDisposable 传播到您的所有班级?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!