在Dispose中清空“using”语句

最近我看到一些代码编写如下:

public void Dipose() { using(_myDisposableField) { } } 

这对我来说似乎很奇怪,我更喜欢看myDisposableField.Dispose();

有什么理由使用“使用”来处理您的对象而不是明确地进行调用?

不,没有。 它只会编译成一个空的try/finally并最终调用Dispose

去掉它。 您将使代码更快,更易读,也许最重要的是(在下面继续阅读时) 在其意图中更具表现力

更新 :它们有点聪明,等效代码需要空检查,根据Jon Skeet的建议,如果涉及multithreading,也会采用本地副本(与标准事件调用模式的方式相同,以避免在null之间发生争用检查和方法调用)。

 IDisposable tmp = _myDisposableField; if (tmp != null) tmp.Dispose(); 

从我在我编写的示例应用程序的IL中可以看到,看起来您还需要直接将_myDisposableField视为IDisposable 。 如果任何类型式实现IDisposable接口并且同时提供public void Dispose()方法,这将非常重要。

此代码也不会尝试复制using时存在的try-finally ,但有人认为这被认为是不必要的。 正如Michael Graczyk在评论中指出的那样, finally的使用提供了针对exception的保护,特别是ThreadAbortException (可能在任何时候发生)。 也就是说,实际发生这种情况的窗口非常小。

虽然,我认为他们这样做的事实并没有真正理解它给予他们的微妙“好处”。

您发布的示例中有一个非常微妙但又邪恶的错误。

虽然它“编译”到:

 try {} finally { if (_myDisposableField != null) ((IDisposable)_myDisposableField).Dispose(); } 

对象应该在using子句中实例化而不是在外部:

您可以实例化资源对象,然后将变量传递给using语句,但这不是最佳实践。 在这种情况下,在控制离开使用块之后,对象仍然在范围内,即使它可能不再能够访问其非托管资源。 换句话说,它将不再完全初始化。 如果您尝试使用using块之外的对象,则可能会导致抛出exception。 因此,通常最好在using语句中实例化对象,并将其范围限制为using块。

– 使用Statement(C#参考)

换句话说,它是肮脏和hacky。

在MSDN上非常清楚地说明了干净的版本:

  • 如果可以将实例的使用限制为方法,则在其边框上using带有构造函数调用的using块。 不要直接使用Dispose
  • 如果您需要(但确实需要)保持实例处于活动状态直到处理完父节点,则使用Disposable模式显式处理,不进行其他操作。 实现一个dispose级联有不同的方法,但是它们需要完全相同,以避免非常微妙和难以捕获错误。 框架设计指南中有一个非常好的MSDN资源。

最后,请注意以下内容:如果使用非托管资源,则只应使用IDisposable模式。 确保它真的需要:-)

using语句定义了应该处理引用对象的代码范围。

是的,你可以在完成后调用.dispose,但不太清楚(恕我直言)对象的范围是什么。 因人而异。