如果我在 using 语句结束之前返回会发生什么?会调用 dispose 吗?

发布于 2024-09-09 02:52:38 字数 295 浏览 5 评论 0原文

我有以下代码

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

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

I've the following code

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

The dispose() method is called at the end of using statement braces } right? Since I return before the end of the using statement, will the MemoryStream object be disposed properly? What happens here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

陌上青苔 2024-09-16 02:52:38

是的,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<无论如何,/code> 都保证被调用。

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

附录:
需要添加一点警告:因为保证调用 Dispose,所以在实现 IDisposable 时确保 Dispose 永远不会抛出异常几乎总是一个好主意。不幸的是,核心库中有一些类在调用 Dispose确实会在某些情况下抛出 - 我正在看着你,WCF 服务参考/客户端代理! -- 当发生这种情况时,如果在异常堆栈展开期间调用 Dispose ,则很难追踪原始异常,因为原始异常会被 生成的新异常所吞噬。 code>Dispose 调用。这可能会让人非常沮丧。或者这令人沮丧、疯狂?两者之一。也许两者都有。

Yes, Dispose will be called. It's called as soon as the execution leaves the scope of the using block, regardless of what means it took to leave the block, be it the end of execution of the block, a return statement, or an exception.

As @Noldorin correctly points out, using a using block in code gets compiled into try/finally, with Dispose being called in the finally block. For example the following code:

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

effectively becomes:

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

So, because finally is guaranteed to execute after the try block has finished execution, regardless of its execution path, Dispose is guaranteed to be called, no matter what.

For more information, see this MSDN article.

Addendum:
Just a little caveat to add: because Dispose is guaranteed to be called, it's almost always a good idea to ensure that Dispose never throws an exception when you implement IDisposable. Unfortunately, there are some classes in the core library that do throw in certain circumstances when Dispose is called -- I'm looking at you, WCF Service Reference / Client Proxy! -- and when that happens it can be very difficult to track down the original exception if Dispose was called during an exception stack unwind, since the original exception gets swallowed in favor of the new exception generated by the Dispose call. It can be maddeningly frustrating. Or is that frustratingly maddening? One of the two. Maybe both.

穿透光 2024-09-16 02:52:38

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))
{

}

using statements behave exactly like try ... finally blocks, so will always execute on any code exit paths. However, I believe they are subject to the very few and rare situations in which finally blocks are not called. One example that I can remember is if the foreground thread exits while background threads are active: all threads apart from the GC are paused, meaning finally blocks are not run.

Obvious edit: they behave the same apart from the logic that lets them handle IDisposable objects, d'oh.

Bonus content: they can be stacked (where types differ):

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

}

And also comma-delimited (where types are the same):

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

}
诠释孤独 2024-09-16 02:52:38

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

Your MemoryStream object will be disposed properly, no need to worry about that.

旧伤慢歌 2024-09-16 02:52:38

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

Take a look at your code in reflector after you compile it. You'll find that the compiler refactors the code to ensure that dispose is called on the stream.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文