如果我在使用声明结束之前返回会发生什么?处理是否会被召唤?

时间:2010-07-14 15:15:29

标签: c# .net dispose idisposable using-statement

我有以下代码

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

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

5 个答案:

答案 0 :(得分:155)

是的,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被调用,无论如何。

有关详细信息,请参阅this MSDN article

附录:
添加一点注意事项:因为保证Dispose被调用,所以确保Dispose在实现IDisposable时永远不会抛出异常几乎总是一个好主意。不幸的是,在调用Dispose的某些情况下,核心库中有一些类抛出 - 我正在看着你,WCF服务参考/客户端代理! - 当发生这种情况时,如果在异常堆栈展开期间调用Dispose,则跟踪原始异常非常困难,因为原始异常被吞下以支持{{1}生成的新异常打电话。这可能令人沮丧。还是令人沮丧地发疯?两个中的一个。也许两者。

答案 1 :(得分:17)

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

明显编辑除了让他们处理IDisposable对象的逻辑之外,它们的行为相同,但是哦。

奖励内容:可以叠加(类型不同):

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

}

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

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

}

答案 2 :(得分:4)

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

答案 3 :(得分:3)

答案 4 :(得分:0)

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