C# 如何在不重置堆栈跟踪的情况下抛出异常?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/730300/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to throw exception without resetting stack trace?
提问by dance2die
This is a follow-up question to Is there a difference between “throw” and “throw ex”?
is there a way to extract a new error handling method without resetting the stack trace?
有没有办法在不重置堆栈跟踪的情况下提取新的错误处理方法?
[EDIT]I will be trying both "inner method" and another answerprovided by Earwicker and see which one can work out better to mark an answer.
[编辑]我将同时尝试“内部方法”和Earwicker 提供的另一个答案,看看哪一个可以更好地标记答案。
采纳答案by Lucero
Not sure if you mean that, but my suggestion in your other question was addressing this.
不确定你的意思,但我在你的另一个问题中的建议是解决这个问题。
If your handler returns a boolean whether the exception was handled or not, you can use this in your catch clause:
如果您的处理程序返回一个布尔值,无论异常是否被处理,您都可以在 catch 子句中使用它:
catch (Exception ex) {
if (!HandleException(ex)) {
throw;
}
}
回答by Adam Robinson
Yes; That's what the InnerException property is for.
是的; 这就是 InnerException 属性的用途。
catch(Exception ex)
{
throw new YourExceptionClass("message", ex);
}
This will allow you to add your own logic, then throw your own exception class. The StackTrace of the YourExceptionClass instance will be from within this code block, but the InnerException will be the exception you caught, with the StackTrace it had before.
这将允许您添加自己的逻辑,然后抛出自己的异常类。YourExceptionClass 实例的 StackTrace 将来自此代码块,但 InnerException 将是您捕获的异常,以及它之前的 StackTrace。
回答by Brian Genisio
You don't want to create a new exception with the original stack trace. That is misleading, since that stack trace did not create the new exception.
您不想使用原始堆栈跟踪创建新异常。这是误导,因为该堆栈跟踪没有创建新的异常。
You can, however, put the original exception in your new exception as an "InnerException". Would that do what you are looking for?
但是,您可以将原始异常作为“InnerException”放入新异常中。那会做你正在寻找的吗?
回答by Daniel Earwicker
Are you catching exceptions that you want to then filter more carefully, so you can then change your mind, decide not to handle them and so rethrow them?
您是否正在捕获要更仔细地过滤的异常,以便您可以改变主意,决定不处理它们并重新抛出它们?
If you want to be really careful about this, that's not really a good idea. It's better to never catch the exception in the first place. The reason is that a given try/catch
handler should not take the decision to run nested finally
blocks for exceptions that it is not expecting to see. For example, if there is a NullReferenceException
, it's probably a very bad idea to continue executing any code as it will probably cause another such exception to be thrown. And finally
blocks are just code, like any other code. As soon as an exception is caught for the first time, any finally
blocks on the stack beneath the try/catch
will be executed, by which time it's too late - another exception may be generated, and this means that the original exception is lost.
如果你想对此非常小心,那不是一个好主意。最好不要一开始就捕获异常。原因是给定的try/catch
处理程序不应该决定为finally
它不希望看到的异常运行嵌套块。例如,如果存在NullReferenceException
,则继续执行任何代码可能是一个非常糟糕的主意,因为它可能会导致抛出另一个此类异常。和finally
块只是代码,就像任何其他代码。一旦第一次捕获到异常,将执行finally
堆栈上的任何块try/catch
,到那时为时已晚-可能会生成另一个异常,这意味着原始异常丢失了。
This implies (in C#) that you have to careful write out a separate catch
handler for all the exception types you want to catch. It also implies that you can only filter by exception type. This is sometimes very hard advice to follow.
这意味着(在 C# 中)您必须为catch
要捕获的所有异常类型小心地编写一个单独的处理程序。这也意味着您只能按异常类型进行过滤。这有时是很难遵循的建议。
It should be possible to filter exceptions in other ways, but in C# it is not. However, it is possible in VB.NET, and the BCL itself takes advantage of this by having a small amount of code written in VB.NET so it can filter exceptions in a more convenient way.
应该可以通过其他方式过滤异常,但在 C# 中则不然。然而,这在 VB.NET 中是可能的,并且 BCL 本身通过在 VB.NET 中编写少量代码来利用这一点,因此它可以以更方便的方式过滤异常。
Here's a detailed explanation, with a VB.NET code sample, from the CLR team blog.
回答by Zarat
With .NET Framework 4.5 there is now an ExceptionDispatchInfowhich supports this exact scenario. It allows capturing a complete exception and rethrowing it from somewhere else without overwriting the contained stack trace.
在 .NET Framework 4.5 中,现在有一个ExceptionDispatchInfo支持这种确切的场景。它允许捕获一个完整的异常并从其他地方重新抛出它而不覆盖包含的堆栈跟踪。
code sample due to request in comment
由于评论中的要求,代码示例
using System.Runtime.ExceptionServices;
class Test
{
private ExceptionDispatchInfo _exInfo;
public void DeleteNoThrow(string path)
{
try { File.Delete(path); }
catch(IOException ex)
{
// Capture exception (including stack trace) for later rethrow.
_exInfo = ExceptionDispatchInfo.Capture(ex);
}
}
public Exception GetFailure()
{
// You can access the captured exception without rethrowing.
return _exInfo != null ? _exInfo.SourceException : null;
}
public void ThrowIfFailed()
{
// This will rethrow the exception including the stack trace of the
// original DeleteNoThrow call.
_exInfo.Throw();
// Contrast with 'throw GetFailure()' which rethrows the exception but
// overwrites the stack trace to the current caller of ThrowIfFailed.
}
}