如果在使用语句结束之前返回,会发生什么情况? 是否调用释放?

我有以下密码

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

dispose()方法在 using语句的末尾被调用,大括号是 }对吗?由于 I returnusing语句结束之前,MemoryStream对象是否被正确处置?这里发生了什么?

34481 次浏览

是的,Dispose将被称为。一旦执行离开 using块的作用域,不管采用什么方法离开该块,也不管是执行块的结束、 return语句还是异常,都会立即调用它。

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

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

有效地变成:

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

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

有关更多信息,请参见 这篇 MSDN 的文章

附录:
只需要补充一点警告: 因为 Dispose肯定会被调用,所以在实现 IDisposable时确保 Dispose永远不会抛出异常几乎总是一个好主意。不幸的是,在 Dispose被调用的某些情况下,在核心库中抛出了一些类——我正在看着你,WCF 服务参考/客户端代理!当这种情况发生时,如果在解除异常堆栈时调用了 Dispose,那么就很难跟踪到原始异常,因为原始异常会被 Dispose调用生成的新异常所吞噬。这真是令人沮丧。还是令人沮丧的疯狂?两者之一。也许两者都有。

您的 MemoryStream 对象将被正确处置,不必担心这个问题。

在编译之后,请在反射器中查看代码。您会发现编译器重构了代码,以确保对流调用释放。

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),
comm2 = new SqlCommand("", conn))
{


}