121

我有以下代码

using(MemoryStream ms = new MemoryStream())
{
     //code
     return 0;
}

该方法在语句大括号dispose()的末尾调用,对吗?由于我 在语句结束之前,对象会被正确处理吗?这里会发生什么?using}returnusingMemoryStream

4

5 回答 5

179

是的,Dispose将被调用。一旦执行离开块的范围,它就会被调用using,无论它以什么方式离开块,无论是块执行结束,return语句还是异常。

正如@Noldorin 正确指出的那样,using在代码中使用块被编译成try/ finally,并Dispose在块中被调用finally。例如下面的代码:

using(MemoryStream ms = new MemoryStream())
{
     //code
     return 0;
}

有效地变成:

MemoryStream ms = new MemoryStream();
try
{
    // code
    return 0;
}
finally
{
    ms.Dispose();
}

因此,因为finally保证在try块完成执行后执行,无论其执行路径如何,Dispose都保证被调用,无论如何。

有关详细信息,请参阅此 MSDN 文章

附录:
只是要补充一点:因为Dispose保证会被调用,所以确保Dispose在实现时永远不会抛出异常几乎总是一个好主意IDisposable。不幸的是,核心库中有一些类在调用时在某些情况下抛出Dispose——我在看你,WCF 服务参考/客户端代理!Dispose- 当这种情况发生时,如果在异常堆栈展开期间调用了原始异常,则可能很难追踪到原始异常,因为原始异常被吞没,有利于Dispose调用生成的新异常。这可能会令人沮丧。还是那令人沮丧的疯狂?两者之一。也许两者兼而有之。

于 2010-07-14T15:17:19.007 回答
19

using语句的行为与try ... finally块完全相同,因此将始终在任何代码退出路径上执行。但是,我相信它们会受到很少和罕见finally的不调用块的情况的影响。我记得的一个例子是,如果前台线程在后台线程处于活动状态时退出:除了 GC 之外的所有线程都被暂停,这意味着finally块没有运行。

明显的编辑:除了让它们处理 IDisposable 对象的逻辑之外,它们的行为相同,d'oh。

奖励内容:它们可以堆叠(类型不同):

using (SqlConnection conn = new SqlConnection("string"))
using (SqlCommand comm = new SqlCommand("", conn))
{

}

还有逗号分隔(类型相同):

using (SqlCommand comm = new SqlCommand("", conn), 
       comm2 = new SqlCommand("", conn))
{

}
于 2010-07-14T15:24:40.563 回答
4

您的 MemoryStream 对象将被正确处理,无需担心。

于 2010-07-14T15:17:23.717 回答
3

使用该using语句,无论完成路径如何,都将处理该对象。

进一步阅读...

于 2010-07-14T15:17:49.307 回答
0

编译后查看反射器中的代码。您会发现编译器重构代码以确保在流上调用 dispose。

于 2010-07-14T15:18:21.220 回答