如何在维护迄今为止生成的堆栈跟踪的同时重新抛出内部异常?
重复: 在 C# 中,如何重新抛出InnerException 不会丢失堆栈跟踪?
我有一些在后台线程上异步调用的操作。 有时,事情会变坏。 当这种情况发生时,我往往会得到一个 TargetInitationException,虽然合适,但毫无用处。 我真正需要的是 TargetInvocationException 的 InnerException,如下所示:
try
{
ReturnValue = myFunctionCall.Invoke(Target, Parameters);
}
catch (TargetInvocationException err)
{
throw err.InnerException;
}
这样,我的调用者就可以得到发生的真实异常。 问题是, throw 语句似乎重置了堆栈跟踪。 我想基本上重新抛出内部异常,但保留其最初的堆栈跟踪。 我怎么做?
澄清: 我只想要内部异常的原因是,此类试图“抽象”这些函数(由调用者提供的委托)在其他线程上运行的整个事实等等。 如果出现异常,那么它很可能与在后台线程上运行无关,并且调用者确实希望进入其委托并找到真正问题的堆栈跟踪,而不是我对 invoke 的调用。
Duplicate of: In C#, how can I rethrow InnerException without losing stack trace?
I have some operations that I invoke asynchronously on a background thread. Sometimes, things go bad. When this happens, I tend to get a TargetInvocationException, which, while appropriate, is quite useless. What I really need is the TargetInvocationException's InnerException, like this:
try
{
ReturnValue = myFunctionCall.Invoke(Target, Parameters);
}
catch (TargetInvocationException err)
{
throw err.InnerException;
}
That way, my callers are served up with the REAL exception that occured. The problem is, that the throw statement seems to reset the stack trace. I'd like to basically rethrow the inner exception, but keep the stack trace it originally had. How do I do that?
CLARIFICATION:
The reason I want only the inner exception is that this class tries to 'abstract away' the whole fact that these functions (delegates supplied by caller) are run on other threads and whatnot. If there is an exception, then odds are it has nothing to do with being run on a background thread, and the caller would really like the stack trace that goes into their delegate and finds the real issue, not my call to invoke.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
可以在重新抛出之前保留堆栈跟踪而不进行反射:
与InternalPreserveStackTrace相比,这会浪费大量周期,但具有仅依赖公共功能的优点。 以下是堆栈跟踪保留函数的一些常见使用模式:
It is possible to preserve the stack trace before rethrowing without reflection:
This wastes a lot of cycles compared to InternalPreserveStackTrace, but has the advantage of relying only on public functionality. Here are a couple of common usage patterns for stack-trace preserving functions:
不,那是不可能的。 您唯一真正的机会是遵循推荐的模式并使用适当的
InnerException
抛出您自己的异常。编辑
如果您担心的是
TargetInvocableException
的存在,并且您想忽略它(不是我推荐这样做,因为它很好与它在另一个线程上运行的事实有关)那么没有什么可以阻止您在这里抛出自己的异常并将TargetInvocalException
中的InnerException
附加为您自己的<代码>内部异常。 它有点臭,但它可能会实现你想要的。No, that isn't possible. Your only real opportunity is to follow the recommended pattern and throw your own exception with the appropriate
InnerException
.Edit
If your concern is the presence of the
TargetInvocationException
and you want to disregard it (not that I recommend this, as it could very well have something to do with the fact that it's being run on another thread) then nothing is stopping you from throwing your own exception here and attaching theInnerException
from theTargetInvocationException
as your ownInnerException
. It's a little smelly, but it might accomplish what you want.有一种方法可以通过使用内部机制来“重置”异常的堆栈跟踪,该内部机制用于在使用远程处理时保留服务器端堆栈跟踪,但这很糟糕:
这会将原始堆栈跟踪放入
_remoteStackTraceString<异常的 /code> 字段,当重新抛出异常时,该字段会连接到新重置的堆栈跟踪。
这确实是一个可怕的黑客,但它确实实现了你想要的。 不过,您正在 System.Exception 类内部进行修改,因此此方法可能会在框架的后续版本中中断。
There is a way of "resetting" the stack trace on an exception by using the internal mechanism that is used to preserve server side stack traces when using remoting, but it is horrible:
This puts the original stack trace in the
_remoteStackTraceString
field of the exception, which gets concatenated to the newly reset stack trace when the exception is re-thrown.This is really a horrible hack, but it does achieve what you want. You are tinkering inside the
System.Exception
class though so this method may therefore break in subsequent releases of the framework.尽管您可能觉得 TargetInitationException “无用”,但这就是现实。 不要试图假装 .NET 没有接受原始异常并将其用 TargetInitationException 包装并抛出。 那确实发生了。 有一天,您甚至可能需要来自该包装的一些信息 - 例如引发 TargetInvocableException 的代码的位置。
Although you may feel that the TargetInvocationException is "useless", it's the reality. Don't try to pretend that .NET didn't take the original exception and wrap it with a TargetInvocationException and throw it. That really happened. Some day, you might even want some piece of information that comes from that wrapping - like maybe the location of the code that threw the TargetInvocationException.
.net 4.5 可以实现:
It is possible with .net 4.5:
你不能那样做。
throw
始终重置堆栈跟踪,除非不带参数使用。 恐怕你的调用者将不得不使用 InnerException...You can't do that.
throw
always resets the stack trace, unless used without parameter. I'm afraid your callers will have to use the InnerException...对异常使用“throw”关键字将始终重置堆栈跟踪。
最好的办法是捕获您想要的实际异常,并使用“throw;” 而不是“扔前;”。 或者抛出您自己的异常,以及您想要传递的 InnerException。
我不相信你想做的事是可能的。
Using the "throw" keyword with an exception will always reset the stack trace.
The best thing to do is to catch the actual exception you want, and use "throw;" instead of "throw ex;". Or to throw your own exception, with the InnerException that you want to pass along.
I don't believe what you want to do is possible.
正如其他人所说,使用“throw”关键字而不添加它以保持异常链完整。 如果您需要原始异常(假设这就是您的意思),那么您可以在链的末尾调用 Exception.GetBaseException() 来获取启动这一切的异常。
As others have said, use the "throw" keyword without adding to it to keep the exception chain intact. If you need that original exception (assuming that is what you mean) then you could call Exception.GetBaseException() at the end of your chain to get the Exception that started it all.