在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,但不太清楚(恕我直言)对象的范围是什么。 因人而异。