当前位置:  开发笔记 > 编程语言 > 正文

c#"finally"阻止只在异常上运行

如何解决《c#"finally"阻止只在异常上运行》经验,为你挑选了5个好方法。

编辑:我看过的答案代码:NONE他们做我想做的(我检查).似乎没有办法在本地c#中做我想要的.鉴于.NET确实支持它,我认为这不是一场灾难(见接受的答案).

谢谢大家.


我有c#代码(测试框架的一部分,除了调试器之外永远不会运行),这样就指出它可以避免实际捕获异常,因为这会使得在堆栈的展开部分调试代码成为一种巨大的痛苦.

Bool bad = true;
try
{
   MightThrow();
   bad = false;
}
finally
{
   if(bad) DoSomeLoggingOnFailure();

   //// Does not catch!!!! 
   //// exception continues to unwind stack.

   //// Note that re throwing the exception is NOT
   //// the same as not catching it in the first place
}

他们是一个更好的方法吗?

对于未捕获的异常,解决方案必须与调试器下的行为完全相同.它必须导致唯一的第一次机会异常,并且调试器在最初抛出异常时断开,而不是在catch块中.

具体来说,我需要在未捕获的异常上调试器来阻止MightThrow.

以下操作无效,因为它无法在正确的位置调试器中断

try { ... } catch { throw; }

这不起作用,因为它丢失了堆栈信息(并且还在错误的地方中断).

try { ... } catch(Excption e) { throw e; }

我知道在D中我可以使用一个scope(failure)



1> Greg Beech..:

因此,在.NET中你所要求的理论上是可行的,但这并不容易.

CIL实际上定义了五种类型的异常处理块!的try,catchfinally那些你在C#中使用,另外两个:

filter- 类似于一个catch块但可以运行任意代码来确定它是否要处理错误,而不仅仅是匹配类型.此块可以访问异常对象,并且对异常堆栈跟踪具有与catch块相同的效果.

fault- 类似于finally块,但它仅在发生异常时运行.此块无法访问异常对象,并且对异常堆栈跟踪没有影响(就像finally块一样).

filter有一些.NET语言(例如VB.NET,C++/CLI)可用,但不幸的是在C#中不可用.但是,除了CIL之外,我不知道允许fault表达块的任何语言.

因为它可以用IL完成,但并不是所有的都丢失了.从理论上讲,您可以使用Reflection.Emit动态发出一个具有fault块的函数,然后将您想要运行的代码作为lambda表达式传递(即一个用于try部分,一个用于错误部分,依此类推),但是(a)这并不容易,而且(b)我不相信这实际上会给你一个比你现在更有用的堆栈跟踪.

对不起,答案不是"这里是怎么做"类型的东西,但至少现在你知道了!你现在正在做的可能是最好的方法恕我直言.


对于那些说问题中使用的方法是"不良实践"的人,请注意事实并非如此.当你实现一个catch块时,你说"当发生异常时我需要对异常对象做一些事情",当你实现一个finally你说"我不需要异常对象,但我需要先做一些事情"之前功能的结束".

如果你真正试图说的是"我不需要异常对象,但是当发生异常时我需要做一些事情"那么你就在两者之间,即你想要一个fault块.由于这在C#中不可用,因此您没有理想的选项,因此您也可以选择不太可能通过忘记重新抛出而导致错误的选项,并且不会破坏堆栈跟踪.



2> Randolpho..:

这个怎么样:

try
{
  MightThrow();
}
catch
{
  DoSomethingOnFailure();
  throw; // added based on new information in the original question
}

真的,这就是你所做的一切.最后是针对必须运行的事情,无论是否发生异常.

[ 编辑:澄清]

根据您提到的注释,您希望在不修改其原始堆栈跟踪的情况下继续抛出异常.在这种情况下,你想使用我添加的朴实的投掷.这将允许异常继续向上堆栈,并仍允许您处理部分异常.典型情况可能是关闭网络连接或文件.

[ 第二次编辑:关于你的澄清]

具体来说,我需要在未捕获的异常上调试器停止在throw的原始点(在MightThrow中)而不是在catch块中.

我反对打破最佳实践(是的,这是部分处理异常的最佳实践),为调试添加一些小的价值.您可以轻松检查异常以确定异常抛出的位置.

[ 最终编辑:你有答案]

kronoz精心为您提供了所寻求的答案.不要破坏最佳实践 - 正确使用Visual Studio!您可以将Visual Studio设置为在抛出异常时完全中断.这是关于这个主题的官方信息.

我实际上并不知道这个功能,所以去给他接受的答案.但请不要试图以某种时髦的方式处理异常只是为了给自己一个手动调试.你所做的就是打开更多的bug.



3> ljs..:

如果您对调试器感兴趣,只需准确地停止发生异常的位置,那么您是否考虑过第一次机会异常?

如果打开"工具"|"异常",然后勾选"公共语言运行时异常"框,则无论是否有任何try/catch/finally块,调试器都将在异常点停止.

更新:您可以通过展开"例外"对话框中的[+]树来指定要捕获的精确异常.虽然每次出现指定类型[s]的任何异常时它都会触发,你甚至可以在调试会话中间随意打开和关闭它,所以明智地使用断点你就可以得到它做你的出价.我成功地使用它来绕过'调用的目标已抛出异常'来自使用反射来实例化对象的球疼.在这种情况下非常有用的工具.另外要注意的当地人和堆栈跟踪应牢固可据我记得(只是做了一个快速测试,他们可用),所以没有问题.

当然,如果你想记录那些超出IDE调试器范围的东西; 在这种情况下,第一次机会异常对你没有帮助!

至少放手一搏; 我发现它们非常有用,它们可能比你想象的更适合你的问题.



4> Rowland Shaw..:

有什么不对:

try
{
   MightThrow();
}
catch
{
   DoSomthingOnFailure();
   throw;
}



5> M4N..:

对于只应在异常上运行的代码,请使用catch块:

try
{
   MightThrow();
}
catch (Exception ex)
{
   // this runs only when there was an exception
   DoSomthingOnFailure();
   // pass exception on to caller
   throw; 
}
finally
{
   // this runs everytime
   Cleanup();
}

推荐阅读
赛亚兔备_393
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有