c# - 使用 IDisposable 管理引用计数

标签 c# idisposable

<分区>

背景:

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

目标:

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

到目前为止:

我有办法做到这一切,但我管理我的“我应该撤消”逻辑吗:

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

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

Maybe I'm not too much of an idiot to screw that up, but what if I had to expose this interface in code I pass down? I would like if the compiler could take care of this for me, if possible.

想法:

我正在考虑为此使用实现 IDisposable 的类。这样,我的代码的用户就可以使用 using block ,而不必担心家务活。这是我目前所拥有的:

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!");
    }
}

我包含了一个 bool 值,这样我确定我不会在 Dispose() 上重复倒计时。因此,要使用 HallPass,您只需:

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

问题是:

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

此外,我对此感到很愚蠢,但我很确定引用计数 不是正确的术语。它就像一个引用计数,但没有管理的引用或释放的内存。 编辑: 可能是,只是现在不行。

它就像一个互斥体或一个关键部分,因为你试图在一个部分中对规则进行异常(另一个用词不当,因为我不是说你throw的那种)代码,但它不是其中任何一个,因为它们在一个范围内是相互排斥的——如果您愿意,这被设计为以嵌套方式完成。这就是为什么它是一个计数,而不是一个 bool 值。

最佳答案

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

下一个更大的问题是您没有真正按照预期的方式使用一次性模式。我个人认为,以应有的方式使用模式很重要,尤其是当您不是唯一一个编写代码的人时。

  1. 而不是记住调用 ResumeUndo(),现在您需要记住您必须调用 Dispose()。问题是:当您的团队成员想要使用 HallPass 时,他们会很自然地意识到他们需要调用 Dispose () 吗? (using 语句很好,但不是所有场景都用,如果有HallPass 的生命周期超过单个方法的作用域,就不能把它包裹起来using 语句)
  2. 虽然忘记调用 IDisposible 上的 Dispose() 很糟糕,但它通常不会影响程序的正确性 - 是的,您的程序会出现性能问题,泄漏等,但在功能上它通常仍然是正确的。但是对于您的 HallPass,如果有人忘记调用 Dispose(),我想会有一个功能错误。而且错误很难追踪。

关于c# - 使用 IDisposable 管理引用计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25827668/

相关文章:

c# - 无法检查 DataList 页脚模板中的 RadioButton

.net - IDisposable 对象的标准集合

c# - 跨不同 Web 浏览器的单点登录

c# - 如何在 Blend 4 中编辑使用 VS2012 创建的 c# 项目?

c# - Coverity、Enumerable.Where(this ...) 和 IDisposable

.net - 'System.Net.Mail.SmtpClient' 类型的“使用”操作数必须实现 'System.IDisposable' - (.NET 3.5)

c# - 我的库应该同时实现 IDisposable 和 IAsyncDisposable 吗?

c# - 使用 block 分解 C# 以启用函数式编程的模式

c# - HttpWebResponse 超时

c# - 你能在 XNA 中打开 NumLock 吗?