应该尝试/捕获在使用块内部或外部
本文关键字:内部 外部 | 更新日期: 2023-09-27 18:31:58
using
块是try/catch/finally
的简写。在我的代码中,我一直在using
块中放置一个try/catch
块,以便我可以使用自己的记录器捕获和记录异常。
我最近一直在想try
是否应该在外面,从而封装using
块。
在我看来,我以前一直担心如果抛出异常,那么using
块不会Dispose()
我的资源,因为它已经跳出块并进入 catch 处理程序。但我可能是错的。
有人可以澄清一下同时使用using
和try/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
声明中的项目(编辑:我的意思是,如果您在try
和catch
块中都需要该项目 - 感谢 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