脚本
我有一个进行数据库操作的方法(比方说).如果在该操作期间引发任何异常,我只想将该异常抛给调用者.我不想在catch块中执行任何特定任务,假设调用者将对该异常执行任何操作.在这种情况下,哪一种是适当的异常处理技术?
try { // Some work that may generate exception } catch(Exception) { throw; } finally { // Some final work }
以上是等于以下try/catch/finally吗?
try { // Some work that may generate exception } catch { throw; } finally { // Some final work }
以上是等于下面的try/finally吗?
try { // Some work that may generate exception } finally { // Some final work }
哪一个比另一个好?应该使用哪一个?
不,他们不等同.在某些情况下,它们可能相同,但一般的答案是否定的.
不同种类的catch
块
catch
具有指定异常类型的块以下内容仅捕获从中继承System.Exception
然后执行finally
块的托管异常,无论是否抛出异常,都会发生这种异常.
try { // Some work that may generate exception } catch (Exception) { throw; } finally { // Some final work }
catch
没有指定异常类型的块catch
没有类型说明符的以下块也将捕获不一定由托管System.Exception
对象表示的非托管异常,然后执行该finally
块,无论是否抛出异常,都会发生该块.
try { // Some work that may generate exception } catch { throw; } finally { // Some final work }
finally
块没有catch
块如果您根本没有catch
阻止,finally
无论是否发生异常,您仍将执行.
try { // Some work that may generate exception } finally { // Some final work }
如果您的catch
块没有指定异常并且只包含该throw;
语句,则后两个确实是等效的.如果您不关心非托管异常,并且您的catch
块仅包含该throw;
语句,则可以认为这三者都是等效的.
throw
以下两段代码包含一些细微差别.后者将重新抛出异常,这意味着它将重写异常的堆栈跟踪,因此这些绝对不等同:
catch (Exception e) { throw; }
和
catch (Exception e) { throw e; }
如果您使用finally
a IDisposable
,以下两段代码几乎相同,但有一些细微差别:
当对象为null时,using
语句不会给你一个NullReferenceException
当使用try
- finally
技术时,变量仍然在范围内,尽管在处理之后使用任何对象都是非常不鼓励的.但是,您仍然可以将变量重新分配给其他内容.
东西obj = null; try {obj = new Something()// do something} finally {obj.Dispose(); }
和
using (var obj = new Something()) { // Do something }
到目前为止,你有一些很好的答案,但到目前为止他们没有提到一个有趣的区别.考虑:
try { ImpersonateAdmin(); DoWork(); } finally { RevertImpersonation(); }
VS
try { ImpersonateAdmin(); DoWork(); } catch { RevertImpersonation(); throw; } finally { RevertImpersonation(); }
假设DoWork抛出.
现在第一个问题是"是否存在可以处理此异常的catch块",因为如果答案为"否",则程序的行为是实现定义的.运行时可能会选择立即终止进程,它可能会选择在终止进程之前运行finally块,它可能会选择在未处理的异常点启动调试器,它可能会选择执行任何喜欢的操作.具有未处理异常的程序可以执行任何操作.
所以运行时开始寻找一个catch块.这个try语句中没有,所以它查找调用堆栈.假设它找到一个带有异常过滤器的.它需要知道过滤器是否允许处理异常,因此过滤器在模拟被还原之前运行.如果过滤器意外或故意做了只有管理员可以做的事情,它就会成功!这可能不是你想要的.
在第二个示例中,catch立即捕获异常,恢复模拟,抛出,现在运行时开始寻找catch块来处理重新抛出.现在,如果有一个过滤器,它将在模拟恢复后运行.(当然最终会再次恢复;我认为恢复模仿在这里是幂等的.)
这是这两个代码片段之间的重要区别.如果绝对禁止积极的任何代码,一看就知道是由尝试搞砸了,并通过清理全局状态最终,那么你最后才赶上."最后"并不意味着"立即",它意味着"最终".