C# 如果在使用语句结束之前返回,会发生什么?会叫警察吗?
我有以下代码C# 如果在使用语句结束之前返回,会发生什么?会叫警察吗?,c#,.net,dispose,idisposable,using-statement,C#,.net,Dispose,Idisposable,Using Statement,我有以下代码 using(MemoryStream ms = new MemoryStream()) { //code return 0; } dispose()方法在的末尾使用语句括号}调用,对吗?由于I在using语句结束之前返回,因此内存流对象是否会被正确处理?这里发生了什么?是,将调用Dispose。只要执行离开using块的作用域,它就会被调用,不管它以什么方式离开块,无论是块的执行结束、return语句还是异常 正如@Noldorin正确指出的,在代码中使用和块
using(MemoryStream ms = new MemoryStream())
{
//code
return 0;
}
dispose()
方法在的末尾使用
语句括号}
调用,对吗?由于I在using
语句结束之前返回
,因此内存流
对象是否会被正确处理?这里发生了什么?是,将调用Dispose
。只要执行离开using
块的作用域,它就会被调用,不管它以什么方式离开块,无论是块的执行结束、return
语句还是异常
正如@Noldorin正确指出的,在代码中使用和块会被编译成try
/finally
,并在finally
块中调用Dispose
。例如,以下代码:
using(MemoryStream ms = new MemoryStream())
{
//code
return 0;
}
实际上成为:
MemoryStream ms = new MemoryStream();
try
{
// code
return 0;
}
finally
{
ms.Dispose();
}
因此,由于finally
保证在try
块完成执行后执行,无论其执行路径如何,Dispose
保证被调用,无论发生什么情况
有关详细信息,请参阅
附录:
需要补充一点:因为Dispose
保证会被调用,所以在实现IDisposable
时,确保Dispose
从不引发异常几乎总是一个好主意。不幸的是,在调用Dispose
时,核心库中有一些类确实会在某些情况下抛出--我在看你,WCF服务引用/客户端代理当这种情况发生时,如果在异常堆栈展开期间调用了Dispose
,则很难跟踪原始异常,因为原始异常会被吞没,而由Dispose
调用生成的新异常会被吞没。这可能令人沮丧得发狂。还是说这令人沮丧?两个中的一个。也许两者都有 您的MemoryStream对象将被正确处理,无需担心 使用using
语句,不管完成路径如何,对象都将被丢弃
进一步阅读
编译后,请查看reflector中的代码。您会发现编译器重构代码以确保在流上调用dispose。使用
语句的行为与try。。。最后
块,因此将始终在任何代码退出路径上执行。但是,我相信它们会受到很少且罕见的情况的影响,在这种情况下,最终
块不会被调用。我记得的一个例子是,如果前台线程退出,而后台线程处于活动状态:除GC之外的所有线程都暂停,这意味着最终
块不会运行
显而易见的编辑:除了让它们处理IDisposable对象的逻辑之外,它们的行为是相同的
奖励内容:可以堆叠(类型不同的地方):
以及逗号分隔(其中类型相同):
我想您会发现,它通过调用finally中的Dispose
,有效地编译成了try-finally块,因此它有效地完成了finally
的实现,正如您所描述的那样。@Noldorin:没错。虽然我想我可以说得很清楚。另请注意,在某些情况下,finally块不能保证执行,例如使用Environment.FailFast和发生StackOverFlowException。@C.McAtackney:这也是一个很好的观点。还有,IIRC,OutOfMemoryException;基本上,如果您无法捕获异常,因为它是一个关键的执行失败,则不会调用Dispose。当然,在这种情况下,程序和分配给它的任何内存都会崩溃,因此在99.9%的情况下,这不是问题,除非你正在做一些不可靠的事情,比如用dispose方法写入文件。除了灾难性的程序崩溃之外,也就是说,您不应该在WCF中使用“using()”语句-有关详细信息,请参阅。下面是我用于WCF代理的一个片段:“WCFProxy variableName=null;尝试{variableName=new WCFProxy();//此处的TODO代码variableName.Proxy.Close();variableName.Dispose();}捕获(异常){if(variableName!=null&&variableName.Proxy!=null){variableName.Proxy.Abort();}throw;}Aaap。。。我收回这句话。经过一些非常认真的搜索之后,我发现了一个近乎重复的问题:现在,这个问题的提问方式完全不同,但最终的问题几乎是一样的。我想我们毕竟可以认为这是一个DUPE。根据StAcExver中的另一个答案,对于第二个例子(逗号分隔),不应该指定第二个参数的类型。我没有回到以前的语言版本,所以我不知道是一直都是这样,还是Roslyn的一个小变化。
using (SqlConnection conn = new SqlConnection("string"))
using (SqlCommand comm = new SqlCommand("", conn))
{
}
using (SqlCommand comm = new SqlCommand("", conn),
comm2 = new SqlCommand("", conn))
{
}