使用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背景,这个成语更广泛。