您如何防止 IDisposable 传播到您的所有班级? [英] How do you prevent IDisposable from spreading to all your classes?

查看:26
本文介绍了您如何防止 IDisposable 传播到您的所有班级?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有这样一组简单的类:

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有一个DriverDriver有两个Shoe,每个Shoe 有一个 鞋带.都非常傻.

A Bus has a Driver, the Driver has two Shoes, 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 传播到您的所有班级?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆