使用IDisposable管理引用计数

时间:2014-09-13 21:00:34

标签: c# idisposable

背景:

this question类似,我希望将IDisposable用于其他设计之外的其他内容。

目标:

这个应用程序并不是非常相关,但仅仅是一个很好的例子:我有一个Windows Forms应用程序,我实现了一个Undo设计模式。通常,这是通过拦截UI元素中的“Value Changed”事件来完成的。对于DataGridViewCellEndEdit等等。但是在某些情况下,我会以编程方式更改数据,并且我希望每个撤消操作都跟踪它们,而不跟踪它们。

到目前为止:

我有办法完成所有这些,但我在计算中管理我的“我应该撤消”逻辑:

private int _undoOverrides = 0;
public bool ShouldUndo { get { return _undoOverrides < 1; } }
public void DoNotUndo() { ++_undoOverrides; }
public void ResumeUndo() { --_undoOverrides; }

现在,这很有效,但您必须记住在以ResumeUndo()开头的业务逻辑结束时调用DoNotUndo()。我想:

  

也许我不是太愚蠢的搞砸了,但是如果我不得不在代码中公开这个接口我会传递下去呢?如果可能的话,我想编译器可以为我处理这个问题。

想法:

我正在考虑使用一个实现IDisposable的类。这样,我的代码的用户可以使用using块,从不担心家务杂事。这就是我到目前为止所做的:

private static int _refCount = 0;
public static int ReferenceCount { get { return _refCount; } }
class HallPass : IDisposable
{
    protected bool bActive;
    public HallPass()
    {
        ++Program._refCount;
        bActive = true;
        Console.WriteLine("Acquired hallpass!");
    }
    public void Dispose()
    {
        if (bActive)
            --Program._refCount;
        bActive = false;
        Console.WriteLine("Hallpass expired!");
    }
}

我添加了一个布尔值,以便我确定我不会在Dispose()上重复计算。因此,使用HallPass所需要做的就是:

using (new HallPass())
{
    // do things...
}

问题是:

这是个好主意吗?为什么这可能是一个坏主意?我应该知道的任何陷阱?

另外,我觉得这很愚蠢,但我很确定引用计数不适合它。它就像一个引用计数,但没有提及管理或内存来释放。 编辑:可能是,现在还不是。

这就像是一个互斥体或一个关键部分,因为你试图在一段代码中做出异常(另一个用词不当,因为我并不是指你throw)那种规则,但是它不是那些因为它们在一个范围内是互斥的 - 如果你愿意的话,它可以用嵌套方式完成。这就是为什么它是一个计数,而不是一个布尔值。

1 个答案:

答案 0 :(得分:2)

我的第一个问题是Program._refCount可以从多个线程访问而且它没有被同步。但你可以说你的应用程序是单线程的。

下一个更大的问题是你并没有真正按照它应该使用的方式使用一次性图案。我个人认为,使用模式应该使用它是很重要的,特别是当你不是唯一正在处理代码的人时。

  1. 现在您需要记住必须致电ResumeUndo(),而不是记得致电Dispose()。问题是:您的团队成员是否自然会意识到他们需要在Dispose ()使用HallPass时致电using? (HallPass语句很好,但不能在每个场景中使用。如果using的生命周期超过单个方法的范围,则无法将其包含在Dispose()中语句)
  2. 虽然忘记在IDisposible上调用HallPass是不好的,但它通常不会影响程序的正确性 - 是的,您的程序会出现性能问题,泄漏等,但功能上通常会仍然是正确的。但对于Dispose(),如果有人忘记拨打{{1}},我认为会有一个功能错误。这个bug很难追查。