我有以下代码
using(MemoryStream ms = new MemoryStream())
{
//code
return 0;
}
在dispose()
语句大括号using
的末尾调用}
方法对吗?由于在return
语句结束之前我using
,MemoryStream
对象是否会正确处理?这里发生了什么?
答案 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)
使用using
语句,无论完成路径如何,都将丢弃对象。
进一步阅读...
答案 4 :(得分:0)
编译后,在反射器中查看代码。您会发现编译器会重构代码以确保在流上调用dispose。