首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何防止IDisposable传播到您的所有班级?

如何防止IDisposable传播到您的所有班级?
EN

Stack Overflow用户
提问于 2009-03-19 11:13:24
回答 5查看 8.6K关注 0票数 139

从这些简单的类开始...

假设我有一组简单的类,如下所示:

代码语言:javascript
复制
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有一个Shoelace。这一切都很愚蠢。

将IDisposable对象添加到鞋带

后来,我决定Shoelace上的一些操作可以是多线程的,所以我为线程添加了一个EventWaitHandle来与之通信。所以Shoelace现在看起来是这样的:

代码语言:javascript
复制
class Shoelace
{
    private AutoResetEvent waitHandle = new AutoResetEvent(false);
    bool tied = false;
    // ... other stuff ..
}

在鞋带上实现IDisposable

但现在Microsoft's FxCop会抱怨:“在‘鞋带’上实现IDisposable,因为它创建了以下IDisposable类型的成员:‘EventWaitHandle’。”

好吧,我在Shoelace上实现了IDisposable,我的小类变得很糟糕:

代码语言:javascript
复制
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)和析构函数:

代码语言:javascript
复制
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

Driver创建Shoe,因此Driver必须为IDisposableBus创建Driver,因此Bus必须为IDisposable,依此类推。

突然,我对Shoelace的小小更改给我带来了很多工作,我的老板想知道为什么我需要签出Bus才能对Shoelace进行更改。

问题是

您如何防止IDisposable的这种传播,同时仍然确保您的非托管对象被正确处理?

EN

回答 5

Stack Overflow用户

发布于 2009-03-19 12:23:28

就正确性而言,如果父对象创建并本质上拥有一个子对象,而这个子对象现在必须是可处理的,则无法阻止通过对象关系传播IDisposable。在这种情况下,FxCop是正确的,并且父级必须为IDisposable。

您可以做的是避免将IDisposable添加到对象层次结构中的叶类。这并不总是一项简单的任务,但它是一个有趣的练习。从逻辑的角度来看,ShoeLace没有理由需要是一次性的。除了在这里添加WaitHandle之外,还可以在使用时添加ShoeLace和WaitHandle之间的关联。最简单的方法是通过Dictionary实例。

如果您可以在实际使用WaitHandle时通过映射将WaitHandle移动到松散关联中,那么您就可以打破这个链条。

票数 20
EN

Stack Overflow用户

发布于 2009-03-19 11:55:55

这基本上就是当您将组合或聚合与Disposable类混合在一起时发生的事情。如前所述,第一个解决方法是重构鞋带中的waitHandle。

话虽如此,当您没有非托管资源时,您可以大大减少Disposable模式。(我仍在寻找这方面的官方参考资料。)

但是您可以省略析构函数和布尔(GC.SuppressFinalize);也许可以稍微清理一下虚拟的空处置(Bool Dispose)。

票数 3
EN

Stack Overflow用户

发布于 2009-03-19 13:39:53

有趣的是,如果按照上面的定义定义Driver

代码语言:javascript
复制
class Driver
{
    Shoe[] shoes = { new Shoe(), new Shoe() };
}

然后,当Shoe被设为IDisposable时,FxCop (v1.36)不会抱怨Driver也应该是IDisposable

但是,如果它是这样定义的:

代码语言:javascript
复制
class Driver
{
    Shoe leftShoe = new Shoe();
    Shoe rightShoe = new Shoe();
}

然后它就会抱怨。

我怀疑这只是FxCop的一个限制,而不是一个解决方案,因为在第一个版本中,Shoe实例仍然是由Driver创建的,仍然需要以某种方式进行处理。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/661815

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档