使用语句与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()方法完全相同的结果。

  • 通过AJAX MVC下载Excel文件
  • 我应该总是使用AndAlso和OrElse操作员吗?
  • 转换List(of object)到List(of string)
  • testing一个对象是否实现了一个接口
  • Lookup()和Dictionary(Of list())之间的区别
  • 从string中删除回车
  • 在VB.NET或C#中使用itextsharp dll读取PDF内容
  • VB相当于C#的默认(T)
  • 9 Solutions collect form web for “使用语句与IDisposable.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(); }