我有以下模式:
private void MyFunction()
{
doStuff();
if (problem())
{
cleanup();
return;
}
doMoreStuff();
if (otherProblem())
{
cleanup();
return;
}
doYetMoreStuff();
}
错误清理代码重复。消除这种情况的显而易见的方法是:
private void MyFunction()
{
try {
doStuff();
if (problem()) throw new MyException();
doMoreStuff();
if (otherProblem()) throw new MyException();
doYetMoreStuff();
}
catch (MyException)
{
cleanup();
return;
}
}
但是,错误情况并非如此 - 这是一个ASP.Net页面,查询字符串中的错误或无数据都会触发错误情况。异常似乎是重复删除错误处理并将其与主代码分离的最明显的方法,但据我所知,接受的最佳实践是不要像这样使用控制流的异常。
这样做的习惯方法是什么?
答案 0 :(得分:3)
对非异常情况使用异常并不是一个好主意,尤其是在抛出异常并在同一方法中捕获异常时。更好的方法是使用一个布尔变量来指示需要清理,并在finally
块内执行清理。
var needsCleanup = true;
try {
doStuff();
if (problem()) return;
doMoreStuff();
if (otherProblem()) return;
doYetMoreStuff();
needsCleanup = false;
} finally {
if (needsCleanup) {
cleanup;
}
}
答案 1 :(得分:1)
你可以使用try .. finally和早期返回。
private void MyFunction()
{
try
{
doStuff();
if (problem())
{
return;
}
doMoreStuff();
if (otherProblem())
{
return;
}
doYetMoreStuff();
}
finally
{
cleanup();
}
}
答案 2 :(得分:1)
finally
块将在执行离开try
块时执行,即使它离开try
块的原因是因为您调用了return
。所以,你可以这样做:
private void MyFunction()
{
try
{
doStuff();
if (problem()) return;
doMoreStuff();
if (otherProblem()) return;
doYetMoreStuff();
}
finally
{
cleanup();
}
}
答案 3 :(得分:0)
如果cleanup()
实际上只是一个方法调用而不是重复。
在这种情况下,我不会使用例外。 您可以轻松地谷歌搜索详细描述为什么在正常流程中使用异常是一个坏主意的文章:主要是影响性能并且可能搞砸性能计数器('抛出的异常数'将毫无意义)。
答案 4 :(得分:0)
当意外发生时,应该抛出异常。
考虑您要在数据库中添加用户,但如果用户名已经存在,您只需要一个错误说明。现在,错误不一定是例外!
bool AddUser(string username)
现在流程看起来像这样:
if(AddUser(username)) {}
else
{
// Notify the user that it didn't work
}
如果在此处抛出异常,应该是因为软件无法连接到数据库,而不是因为用户名已经存在。
像这样抛出和捕获流控制的异常将导致比所需更多的开销,因此你应该使用if
/ else
来控制它。