应该尝试/捕获在使用块内部或外部

本文关键字:内部 外部 | 更新日期: 2023-09-27 18:31:58

我相信

using块是try/catch/finally的简写。在我的代码中,我一直在using放置一个try/catch块,以便我可以使用自己的记录器捕获和记录异常。

我最近一直在想try是否应该在外面,从而封装using块。

在我看来,我以前一直担心如果抛出异常,那么using块不会Dispose()我的资源,因为它已经跳出块并进入 catch 处理程序。但我可能是错的。

有人可以澄清一下同时使用usingtry/catch的正确方法吗?

public HttpResponseMessage GetData(string x, int y)
{
    using (var client = new HttpClient())
    {
        try
        {
            // do stuff
            return response.Result;
        }
        catch (Exception ex)
        {
            // Something has gone badly wrong so we'll need to throw
            // Log the info
            throw;
        }
    }
}

应该尝试/捕获在使用块内部或外部

using

用于确保一旦代码超出using块,就立即处置(从模棱两可的"立即处置"术语更改为 James 先生建议的处置using)。这不完全try/catch/finally的简写。(请注意,编译器将其解释为 try-finally 但是)

在您的示例中

using (var client = new HttpClient())
{
} //client will be disposed at any time after this line

根据情况,您可以考虑将try-catch块放在using块的内部或外部。

例如,如果您不需要多次使用using声明中的项目(编辑:我的意思是,如果您在trycatch块中都需要该项目 - 感谢 Cody Gray 先生的输入) - 也就是说,您只需要try, 我建议在try块内使用using块。

翻译成您的情况,这取决于var client是否旨在同时用于try块和catch块。如果是,则using应位于try-catch块之外。否则,它应该在try块内。

通常,根据经验,如果该项目同时在try块和catch块中使用,则仅在try-catch外部声明一次using

这实际上取决于您担心被处置的资源 - 如果您指的是client您应该没问题。我会解释为什么...

在我看来,我以前一直担心如果抛出异常,那么使用块将不会处理我的资源,因为它已经跳出块并进入 catch 处理程序。但我可能是错的。

这不是它的工作原理,编译器可能会像这样重写您的代码(可能更有效):

try
{
    try
    {
        // do stuff
        return response.Result;
    }
    catch (Exception ex)
    {
        // Something has gone badly wrong so we'll need to throw
        // Log the info
        throw;
    }
}
finally
{
    if (client != null)
        client.Dispose();
}

正常情况下,finally块将始终执行,这意味着即使您在using中捕获/重新抛出异常,您的Dispose调用也会被触发。

因此,从技术角度来看,内部与外部并不重要。

它没有"正确的方法",只有指导方针。但是,我自己尝试尽可能本地化每个异常或任何代码,这意味着您应该在可以抛出异常的地方抛出异常,但在外面的某个地方,至少只要您不必让您的异常通过不同的层冒泡。

任何一种方式都可以。使用块保证在退出时始终调用 Dispose() 方法 - 即使对于堆栈解开在堆栈下方捕获的异常也是如此。

查看使用语句(C# 参考)

using 语句可确保调用 Dispose,即使在对对象调用方法时发生异常也是如此。您可以通过将对象放入 try 块中,然后在 finally 块中调用 Dispose 来实现相同的结果;事实上,编译器就是这样翻译 using 语句的。前面的代码示例在编译时扩展为以下代码(请注意额外的大括号,以便为对象创建有限的范围):

就个人而言,我会将 try/catch/finally 放在 using 块内。
这样做的原因很简单,using块本身不会引发异常,至少根据我的经验不会。因此,为了简单起见,我会处理异常发生的地方。

using编译到 try/finally 时,只需使用 try/catch/finally 即可。 "无论是否抛出异常,finally 块始终执行。"

var client = new HttpClient();
try
{
    // do stuff
    return response.Result;
}
catch (Exception ex)
{
    // Something has gone badly wrong so we'll need to throw
    // Log the info
    throw;
}
finally
{
    if (client != null)
        client.Dispose();
}

最后一个块也可以减少到 c# 6 及更高版本的 client?.Dispose();

综上所述,HttpClient是一个特例。是的,它是一次性的,但您应该小心动态创建和处置,尤其是在长期存在的应用程序中,并且使用单个共享实例可能会更好。

https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/https://medium.com/@nuno.caneco/c-httpclient-should-not-be-disposed-or-should-it-45d2a8f568bc