使用finally而不是catch
我现在已经看过这种模式了几次:
bool success = false; try { DoSomething(); success = true; } finally { if (!success) Rollback(); }
我一直在想:为什么这比使用catch回滚更好?
try { DoSomething(); } catch { Rollback(); throw; }
确保更改在失败时回滚的两种方法之间有什么区别?
这里明确的目标是在发生任何错误时调用Rollback
。 两个代码片段都实现了这一目标。 第一个使用始终运行的finally,validationtry
块的最后一行是否已成功到达。 第二个捕获任何错误,回滚事务,然后重新抛出捕获的exception。 任何一个片段的结果都是抛出的任何exception都会导致回滚,同时仍然冒泡到下一个级别。
您提到该项目是从Java移植的。 在Java中,您可以像使用throw;
在C#中重新抛出exception throw;
。 您还可以抛出一个仍然维护调用堆栈的新exception (等)。 第二个在C#中更清晰/更简单(虽然不是很多),第一个具有实际使用Java编写的优势。
我在这里发布了一些代码,即使它与问题没有关系(稍后会删除)。
有了这个程序:
using System; namespace testcs { class Program { static void Main(string[] args) { try { try { foo(); foo(); foo(); } catch { throw; } } catch (Exception e) { Console.WriteLine(e.ToString()); } } private static void foo() { throw new Exception("oops"); } } }
堆栈跟踪(查看行号!)被保留,但在main
函数中你会看到“第19行”, throw
所在的行是foo()
被调用的真行(第13行)。
finally
语句通常用于清理资源。 如果exception不是回滚事务的唯一原因,那么Rollback()
方法可以在那里使用。 Close()
或Dispose()
方法是最终块中的主要候选者。
但是,您不希望执行任何可以抛出exception的内容。
如果您不关心此特定代码,您使用的是什么类型的exception:
try { DoSomething(); ok = true; } finally { if(!ok)Rollback(); }
这将以原始forms保留调用堆栈100%。 此外,如果你使用这样的例外加工:
try { DoSomething(); ok = true; } catch(FirstExcetionType e1) { //do something } catch(SecondExcetionType e2) { //do something } catch(Exception e3) { //do something } finally { if(!ok)Rollback(); }
最后使用finally可以使您的代码比从每个catch语句调用回滚更具可读性。
我不确定这不仅仅是轶事证据 ,但我个人使用这种模式是出于一个非常实际的原因:当DoSomething
抛出exception时,Visual Studio调试器将在DoSomething
中破坏,其中第一个版本中发生exception,而它将在throw;
时突破throw;
在第二个版本。 这允许在Rollback
清除所有内容之前检查应用程序状态。
finally
总是执行,不仅仅是捕获exception。
当然,在这种特定情况下,仅在出现错误时才需要回滚,但作为一般模式, try-finally
可能对资源管理更有用(通常需要确保始终为Close()
或Dispose()
你的资源正确)。 特别是如果代码的作者来自Java背景,这个成语更广泛。