使用语句与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
来调用块。 “手工”处置会更好的唯一常见情况是:
- 一个方法调用一个工厂方法,返回一些可能实现或不实现“IDisposable”的东西,但是如果是的话(这是非generics的`IEnumerable.GetEnumerator()`发生的情况)应该是`Dispose`d。 精心devise的工厂接口应该返回一个实现`IDisposable`的types(也许是一个无所作为的实现,通常是IEnumerator`的情况),否则指定的调用者不需要“Dispose”返回的对象。 不幸的是,像非genericsIEnumerable这样的接口既不符合标准。 请注意,在这种情况下,不能很好地使用`using`,因为它仅适用于声明types实现“IDisposable”的存储位置。
- 即使在块被退出之后,“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(); }