当你使用`using`语句时,什么时候需要调用IDisposable?

4

我正在阅读另一个答案。这让我想知道,如果我使用using语句,什么时候需要显式调用Dispose?

编辑:

只是为了证明自己不是完全无知,我问的原因是因为另一条线程上的某个人说了一些暗示必须手动调用Dispose的好理由...所以我想,为什么不问问呢?


我喜欢在StackOverflow上看到这些看似简单的问题。我总是惊讶于从这样一个问题中可以得到多少信息。我之前不知道对象初始化器的问题... - Patrick Klug
SO绝对是一个很棒的网站。我喜欢这里。 - Alex Baranosky
6个回答

20

不需要这样做。使用 using 语句会自动帮你完成。


根据 MSDN,以下示例代码:

using (Font font1 = new Font("Arial", 10.0f)) 
{
    byte charset = font1.GdiCharSet;
}

当编译时,会将其扩展为以下代码(请注意额外的花括号以创建对象的有限作用域):

{
  Font font1 = new Font("Arial", 10.0f);
  try
  {
    byte charset = font1.GdiCharSet;
  }
  finally
  {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}
注意:正如@timvw提到的那样,如果你在using语句中链接方法或使用对象初始化器,并且抛出异常,则该对象将不会被处理。如果您查看它将扩展为什么,这是有道理的。例如:
using(var cat = new Cat().AsDog())
{
   // Pretend a cat is a dog
}

扩展为

{
  var cat = new Cat().AsDog(); // Throws
  try
  {
    // Never reached
  }
  finally
  {
    if (cat != null)
      ((IDisposable)cat).Dispose();
  }
}    

AsDog 显然会抛出异常,因为猫永远不可能像狗一样优秀。那么这只猫将永远不会被处理掉。当然,有些人可能会辩称猫不应该被处理掉,但那是另一个讨论...

无论如何,确保你在 using( 这里 ) 中所做的是安全的,这样你就可以放心了。(显然,如果构造函数失败,对象就不会被创建,所以也不需要处理掉)。


这真是太棒了,当我阅读这篇文章时,广告上的一只比格犬正在Careers.stackexchange.com上寻找工作。 - Michael Brown

12

通常情况下,不需要这么做。这就是使用using语句的目的。然而有一种情况你需要小心:

如果你将变量重新赋值给另一个值,则using语句只会对原始值调用Dispose方法。

using (someValue = new DisposableObject())
{
    someValue = someOtherValue;
}

编译器甚至会对此发出警告:

可能是对本地变量 'someValue' 的错误赋值,该变量是 using 或 lock 语句的参数。Dispose 调用或解锁操作将在本地变量的原始值上执行。


1
我相信在C# 3.5中,这个警告被改成了一个错误:"error CS1656: Cannot assign to 'someValue' because it is a 'using variable'"。 - Dathan

10

5
从不。在 using 块内部的语句执行完毕后,它将调用 Dispose。

3
使用using语句的整个意义在于,如果您的对象实现了IDisposable接口,那么dispose方法将在代码块结束时被调用。这就是它的作用,为您自动执行此操作。

3
据我所知:
using (var myDisposable = new MyDisposable())
{
   ...
}

基本上是由编译器翻译为

var myDisposable = new MyDisposable()
try
{
   ...
}
finally
{
   myDisposable.Dispose();
}

1
它还用大括号将整个代码块封装起来,以限制 myDisposable 的范围,并在 finally 块中添加了一个检查,仅对 myDisposable 的非空实例执行 Dispose()。 - Dathan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接