我正在编写一个组件,它在顶层通过反射调用方法.为了使我的组件更容易使用,我想捕获被调用方法抛出的任何异常并解开它们.
因此,我有类似的东西:
try { method.Invoke(obj, args); }
catch (TargetInvocationException ex) {
throw ex.InnerException;
}
Run Code Online (Sandbox Code Playgroud)
但是,这会吹走内部异常堆栈跟踪.我不能在throw这里使用(因为我正在重新抛出一个不同的异常对象).我可以在catch块中做些什么来确保原始异常类型,消息和堆栈跟踪都能通过?
这样做是不好的形式,因为它不保留堆栈跟踪:
try { /*... some code that can throw an exception ...*/ }
catch (Exception e)
{
throw e; // ...Use "throw;" by itself instead
}
Run Code Online (Sandbox Code Playgroud)
但是,如果在非UI线程上捕获到异常,我想将其重新提升回UI并处理它,以便用户获取如下消息:
try { /*... some code that can throw an exception ...*/ }
catch (Exception e)
{
Dispatcher.Invoke((Action)(() => { throw; }));
}
Run Code Online (Sandbox Code Playgroud)
但是,我不能在这里单独使用throw关键字,因为C#lexer(正确)认为throw语句不在catch中.我不得不这样做:
try { /*... some code that can throw an exception ...*/ }
catch (Exception e)
{
Dispatcher.Invoke((Action)(() => { throw e; }));
}
Run Code Online (Sandbox Code Playgroud)
并重新抛出异常,这会丢失其堆栈跟踪.
是否有任何(简单)方法来解决这个问题(我总是可以在异常准备切换线程时打包堆栈跟踪,但这看起来很糟糕)?
注意:我看到了 …
如何检测何时从catch块中调用当前正在执行的代码?
void SomeFunction()
{
// how do I detect whether I am being called from within a catch block?
}
Run Code Online (Sandbox Code Playgroud)
编辑:
对于那些要求,我想实现这样的类,不要错过错误冒泡逻辑:在编写此代码示例时,我收到编译器错误"在catch子句之外不允许使用不带参数的throw语句"所以无论如何,这有点摧毁了我的想法.
public class ErrorManager {
public void OnException(Exception ex) {
LogException(ex);
if (IsInsideCatchBlockAlready()) {
// don't destroy the stack trace,
// but do make sure the error gets bubbled up
// through the hierarchy of components
throw;
} else {
// throw the error to make it bubble up
// through the hierarchy of components
throw ex;
}
} …Run Code Online (Sandbox Code Playgroud) 我已经尝试了一些关于如何在抛出异常时在堆栈跟踪中保留正确行号的建议。最常见的就是接住然后扔掉,但这不起作用。以下是我尝试过的一些:
private void button1_Click(object sender, EventArgs e)
{
try
{
test();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void test()
{
try
{
int a = 1;
int b = 0;
int x = 0;
x = a / b;
}
catch
{
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
还有 catch 块的一些变化。
catch (Exception)
{
throw;
}
catch (Exception e)
{
throw;
}
catch (Exception e)
{
throw e;
}
Run Code Online (Sandbox Code Playgroud)
所有这些都在抛出行和消息框行上报告错误 - 永远不会在除以 0 的行上报告错误。如果我在 test() 函数内部中断,它确实会显示正确的行 #,但在抛出后不会显示错误。唯一有效的方法是在 test() 函数中不要有任何 try/catch。但当然我希望能够捕获错误并重新抛出它们并保持堆栈跟踪正确。那么这是如何做到的呢? …
我需要重新抛出一个被捕获并存储在其他地方的异常,而不会丢失有关何时首次捕获/存储异常的堆栈跟踪信息.我的代码看起来像这样:
public void Test()
{
int someParameter = 12;
ExecuteSomeAsyncMethod(someParameter, CallbackMethod);
}
public void CallbackMethod(object result, Exception error)
{
//Check for exceptions that were previously caught and passed to us
if(error != null)
//Throwing like this will lose the stack trace already in Exception
//We'd like to be able to rethrow it without overwriting the stack trace
throw error;
//Success case: Process 'result'...etc...
}
Run Code Online (Sandbox Code Playgroud)
我已经看到了这个使用反射的问题的解决方案(例如这里和这里)或使用序列化(例如这里)但是这些都不适用于我在Silverlight中(不允许私有反射,并且使用的是类/方法) Silverlight中不存在序列化方法).
有没有办法保留在Silverlight中工作的堆栈跟踪?
我有一个我正在处理的FileSystemWatch程序,如果复制文件时出错,我希望能够知道它失败了哪个文件.同时,我希望能够保留堆栈跟踪以及内部异常信息.
if (!found)
{
try
{
File.Copy(file, Path.Combine(watchDirectory, filename));
}
catch (Exception ex)
{
WriteToLog(new Exception(
String.Format("An error occurred syncing the Vault location with the watch location. Error copying the file {0}. Error = {1}", file, ex.Message), ex.InnerException));
}
}
Run Code Online (Sandbox Code Playgroud)
所以,传递的异常,我仍然想要堆栈跟踪信息,内部异常信息,但我希望"消息"是我的自定义消息,其中包含失败的文件,同时还显示"真实"原始异常抛出的消息.
我们正在研究使用Unity来处理带有拦截的日志服务方法.但是,一个问题是呼叫站点没有完整的堆栈跟踪; 它只在拦截器调用中可用.
这是一个示例设置:
public interface IExceptionService
{
void ThrowEx();
}
public class ExceptionService : IExceptionService
{
public void ThrowEx()
{
throw new NotImplementedException();
}
}
public class DummyInterceptor : IInterceptionBehavior
{
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
IMethodReturn ret = getNext()(input, getNext);
if (ret.Exception != null)
Console.WriteLine("Interceptor: " + ret.Exception.StackTrace + "\r\n");
return ret;
}
public bool WillExecute
{
get { return true; }
}
}
class Program
{
static void Main(string[] …Run Code Online (Sandbox Code Playgroud) 我惊呆了。我一直认为throw在 catch 块中本身会抛出手头的异常而不改变堆栈跟踪,但throw ex在 catch 块中会更改堆栈跟踪以显示源自语句位置的异常。
采取以下两个代码块。我希望输出会略有不同,因为一个使用throw而另一个使用throw ex,但两者之间的输出是相同的,并且在两种情况下引发初始异常的实际源代码行都丢失了,这对我来说似乎很糟糕。我缺少什么?
第一个示例的行为符合我的预期:
using System;
public class Program
{
public static void Main()
{
try
{
DummyWork();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private static void DummyWork()
{
try
{
throw new Exception("dummy");
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw ex; // I would expect to lose the information about the inciting line 5 above this one in this case.... and I do.
} …Run Code Online (Sandbox Code Playgroud) 一个Exception对象有一个StackTrace属性。但它只是一个字符串。
有没有办法从 中获取实际System.Diagnostics.StackTrace对象Exception?
我问是因为我从 an 获取 Exception 对象,但UnhandledExceptionEventHandler我无权访问生成异常的框架来获取实际的堆栈跟踪。
在我的代码库中,我有一些重试功能,它将异常存储在变量中,最后在变量中抛出异常。想象一下这样的事情
Exception exc = null;
while(condition){
try {
// stuff
} catch (Exception e){
exc = e;
}
}
if (e != null){
throw e;
}
Run Code Online (Sandbox Code Playgroud)
现在,由于这是一条throw e语句而不是一条throw语句,因此原始堆栈跟踪丢失了。有没有办法进行重新抛出以保留原始堆栈跟踪,或者我需要重组我的代码以便我可以使用语句throw?
c# ×9
.net ×6
exception ×6
catch-block ×1
reflection ×1
rethrow ×1
silverlight ×1
stack-trace ×1
try-catch ×1
wpf ×1