使用语句与IDisposable.Dispose()

我的理解是,一旦代码退出块,.NET中的using语句将调用一个IDisposable对象的Dispose()方法。

using语句是否还有其他的用法? 如果不是这样,那么以下两个代码示例看起来完全相同:

 Using Con as New Connection() Con.Open() 'do whatever ' End Using Dim Con as New Connection() Con.Open() 'do whatever ' Con.Dispose() 

无论谁证实我是对的,我都会给出最好的答案,或者指出我错了,并解释了原因。 请记住,我知道某些类可以Dispose()方法中做不同的事情 。 这个问题是关于using语句是否达到与调用对象的Dispose()方法完全相同的结果。

using基本上相当于:

 try { // code } finally { obj.Dispose(); } 

所以它也有调用Dispose()的好处,即使在块内的代码中抛出一个未处理的exception。

正如布莱恩·华沙Brian Warshaw )在这里所说的那样,它只是一个try的障碍,并finally阻止确定对象被处置。 除了他的回答, using块也确保即使您使用范围 返回内部对象也被丢弃

我曾经好奇这个,并用下面的方法进行testing:

自定义IDisposabletesting类和Main

 private class DisposableTest : IDisposable { public string Name { get; set; } public void Dispose() { Console.WriteLine("{0}.Dispose() is called !", Name); } } public static void Main(string[] args) { try { UsingReturnTest(); UsingExceptionTest(); } catch { } try { DisposeReturnTest(); DisposeExceptionTest(); } catch { } DisposeExtraTest(); Console.ReadLine(); } 

testing用例实现

 private static string UsingReturnTest() { using (DisposableTest usingReturn = new DisposableTest() { Name = "UsingReturn" }) { return usingReturn.Name; } } private static void UsingExceptionTest() { using (DisposableTest usingException = new DisposableTest() { Name = "UsingException" }) { int x = int.Parse("NaN"); } } private static string DisposeReturnTest() { DisposableTest disposeReturn = new DisposableTest() { Name = "DisposeReturn" }; return disposeReturn.Name; disposeReturn.Dispose(); // # IDE Warning; Unreachable code detected } private static void DisposeExceptionTest() { DisposableTest disposeException = new DisposableTest() { Name = "DisposeException" }; int x = int.Parse("NaN"); disposeException.Dispose(); } private static void DisposeExtraTest() { DisposableTest disposeExtra = null; try { disposeExtra = new DisposableTest() { Name = "DisposeExtra" }; return; } catch { } finally { if (disposeExtra != null) { disposeExtra.Dispose(); } } } 

输出是:

  • UsingReturn.Dispose()被调用!
  • UsingException.Dispose()被调用!
  • 调用DisposeExtra.Dispose()!
 //preceeding code using (con = new Connection()) { con.Open() //do whatever } //following code 

等同于以下内容(注意con的有限范围):

 //preceeding code { var con = new Connection(); try { con.Open() //do whatever } finally { if (con != null) con.Dispose(); } } //following code 

这在这里描述: http : //msdn.microsoft.com/en-us/library/yh598w02.aspx

using语句确保即使在对象上调用方法时发生exception,也会调用Dispose。 你可以通过把对象放在一个try块中,然后在finally块中调用Dispose来获得相同的结果。 实际上,这就是编译器如何翻译using语句

using语句比try...finally{Dispose()}更清晰,更简洁try...finally{Dispose()}构造,几乎所有的情况下都不应该使用Dispose来调用块。 “手工”处置会更好的唯一常见情况是:

  1. 一个方法调用一个工厂方法,返回一些可能实现或不实现“IDisposable”的东西,但是如果是的话(这是非generics的`IEnumerable.GetEnumerator()`发生的情况)应该是`Dispose`d。 精心devise的工厂接口应该返回一个实现`IDisposable`的types(也许是一个无所作为的实现,通常是IEnumerator`的情况),否则指定的调用者不需要“Dispose”返回的对象。 不幸的是,像非genericsIEnumerable这样的接口既不符合标准。 请注意,在这种情况下,不能很好地使用`using`,因为它仅适用于声明types实现“IDisposable”的存储位置。
  2. 即使在块被退出之后,“IDisposable”对象仍然存在(如设置“IDisposable”字段或从工厂方法返回“IDisposable”时)。

请注意,从工厂方法返回一个IDisposable时,应该使用类似下面的内容:

   bool ok = false;
   DisposableClass myThing;
  尝试
   {
     myThing = new DisposableClass();
     ...
     ok = true;
    返回myThing;
   }
  最后
   {
    如果(!ok)
     {
       if(myThing!= null)
         myThing.Dispose();
     }
   }

确保myThing将得到Dispose d如果它没有得到返回。 我希望有一种方法可以和一些“取消处理”方法一起使用,但是不存在这种情况。

两者的区别在于,如果抛出exception

 Con.Open() 'do whatever 

Con.Dispose不会被调用。

我不是在VB语法,但在C#中,等效的代码将是

 try { con = new Connection(); // Do whatever } finally { if (con != null) con.Dispose(); } 

using语句保证在抛出exception的情况下抛出对象。 这相当于在finally块中调用dispose。

使用块确保在抛出exception时调用Dispose()

你的第二个样本不这样做。

如果Con.Open()抛出一个exception,在第一种情况下,你保证Con.Dispose()被调用。 在第二种情况下,exception传播并Con.Dispose()不会被调用。

使用封装块封装在try / finally中,在finally块中调用Dispose。 这确保了即使发生exception也会调用Dispose。

出于安全原因,您几乎应该在所有情况下使用

如果内存服务,使用是一个对象被处置的保证,不pipe它围绕的代码块如何退出。 它通过在一个try … finally块中包含该块,然后检查所使用的variables是否为null,然后如果它不为null,则将其废弃。 如果抛出一个exception,它可以让堆栈冒泡。 除此之外,它所做的只是保证处理非零废弃物。

 try { var myDisposable = new DisposableObject(); myDisposable.DoSomething(); } finally { if (myDisposable != null) ((IDisposable)myDisposable).Dispose(); }