c# - 如何在 C# 中执行 C++ 样式的析构函数?

标签 c# dispose idisposable using

我通过 IDisposable 获得了一个带有 Dispose 函数的 C# 类。它旨在在 using block 内使用,因此它处理的昂贵资源可以立即释放。

问题是在调用Dispose之前抛出异常时出现bug,而程序员忽略了使用usingfinally .

在 C++ 中,我从来不用担心这个。对类的析构函数的调用将自动插入到对象作用域的末尾。避免这种情况发生的唯一方法是使用 new 运算符并将对象保存在指针后面,但这需要程序员做额外的工作,这不是他们偶然会做的事情,比如忘记使用 using.

有什么方法可以在 C# 中自动使用 using block ?

非常感谢。

更新:

我想解释一下为什么我不接受终结者的答案。这些答案本身在技术上是正确的,但它们不是 C++ 风格的析构函数。

这是我发现的错误,简化为基本要素...

try
{
    PleaseDisposeMe a = new PleaseDisposeMe();
    throw new Exception();
    a.Dispose();
}
catch (Exception ex)
{
    Log(ex);
}

// This next call will throw a time-out exception unless the GC
// runs a.Dispose in time.
PleaseDisposeMe b = new PleaseDisposeMe();

使用 FXCop 是一个很好的建议,但如果这是我唯一的答案,我的问题将不得不成为对 C# 人员的请求,或者使用 C++。有人有二十个嵌套的 using 语句吗?

最佳答案

在我工作的地方,我们遵循以下准则:

  • 每个 IDisposable 类必须有一个终结器
  • 无论何时使用 IDisposable 对象,都必须在“using” block 中使用。唯一的异常(exception)是对象是另一个类的成员,在这种情况下,包含类必须是 IDisposable 并且必须在其自己的“Dispose”实现中调用成员的“Dispose”方法。这意味着除非在另一个“Dispose”方法中,否则开发人员永远不应调用“Dispose”,从而消除问题中描述的错误。
  • 每个终结器中的代码必须以警告/错误日志开头,通知我们终结器已被调用。这样,您就有很大的机会在发布代码之前发现上述错误,而且它可能是您系统中出现错误的提示。

为了让我们的生活更轻松,我们的基础设施中还有一个 SafeDispose 方法,它在 try-catch block 中调用其参数的 Dispose 方法(带有错误日志记录),以防万一(尽管不应该使用 Dispose 方法抛出异常)。

另请参阅:Chris Lyon关于 IDisposable 的建议

编辑: @Quarrelsome:你应该做的一件事是在“Dispose”中调用 GC.SuppressFinalize,这样如果对象被处置,它就不会被“重新处置”。

通常还建议持有一个标志,指示该对象是否已被处置。以下模式通常很好:

class MyDisposable: IDisposable {
    public void Dispose() {
        lock(this) {
            if (disposed) {
                return;
            }

            disposed = true;
        }

        GC.SuppressFinalize(this);

        // Do actual disposing here ...
    }

    private bool disposed = false;
}

当然,锁定并不总是必要的,但如果您不确定您的类是否会在多线程环境中使用,建议保留它。

关于c# - 如何在 C# 中执行 C++ 样式的析构函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47612/

相关文章:

c# - 按父原始消息分组的消息答案

c# - QueryObject 包含 Entity Framework

java - Libgdx 音乐未正确处理

c# - 哪个类 "owns"是非托管资源(并且实现了 IDisposable)?

c# - GraphicsDevice 在我的 XNA Windows 游戏项目中为空

c# - 我应该什么时候调用 SerialPort.Dispose() 与 SerialPort.Close()?

c# - 如果其他构造函数创建它,我应该处置通过构造函数传递的对象吗?

.net - CommonDialog 组件应该如何处理?

c# - 在 "using(object that implements iDisposable)"语句中返回方法是否正确?

C# - 通过属性之一查找控件