我遇到一个问题,当通过func访问的方法中抛出异常时,堆栈跟踪会被截断。考虑以下简单的再现:
static void Main(string[] args)
{
Test();
Console.ReadLine();
}
public static void Test()
{
try
{
Func<string> func = () => MyFunc();
func();
}
catch (Exception ex)
{
Console.WriteLine("Exception.StackTrace:");
Console.WriteLine(ex.StackTrace.ToString());
}
}
public static string MyFunc()
{
Console.WriteLine("Environment.StackTrace:");
Console.WriteLine(Environment.StackTrace);
Console.WriteLine(new String('*', 20));
throw new Exception("Where is my stack trace?");
}
我希望在catch块中写出的堆栈跟踪与MyFunc
中写出的堆栈跟踪基本相同,但事实上,作为异常的堆栈跟踪写出的是:
at FuncStackTraceIssue.Program.MyFunc() in Program.cs:line 36
at FuncStackTraceIssue.Program.<>c.<Test>b__1_0() in Program.cs:line 21
at FuncStackTraceIssue.Program.Test() in Program.cs:line 22
正如您所看到的那样,它只会返回到我调用func(Test
)的函数。在MyFunc中写出堆栈跟踪是:
at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at FuncStackTraceIssue.Program.MyFunc() in Program.cs:line 34
at FuncStackTraceIssue.Program.<>c.<Test>b__1_0() in Program.cs:line 21
at FuncStackTraceIssue.Program.Test() in Program.cs:line 22
at FuncStackTraceIssue.Program.Main(String[] args) in Program.cs:line 13
这导致我出现问题的原因是,在实际代码中,这是从几个不同的地方调用并传入变量和其他类似的东西,当它出错时我记录包括堆栈跟踪在内的异常。我希望能够确切地看到导致错误的代码路径,并且最好不必更改我的记录方式。
所以问题是为什么我没有获得完整的堆栈跟踪,我能做些什么来让它给我一个完整的堆栈跟踪?
答案 0 :(得分:1)
要添加@Dark Falcon上面的评论:
这不一定是Func<>
的问题,但与StackTrace
属性的工作方式有关。
来自MSDN's exception class docs(强调我的):
“相反,如果使用该语句重新抛出异常 [示例如下] ... 不保留完整的调用堆栈,并且 示例将生成以下输出[示例如下] ... A 稍微麻烦的替代方法是抛出一个新的异常,并且 保留原始异常的调用堆栈信息 内在的例外。然后调用者可以使用新的异常 InnerException属性,用于检索堆栈帧和其他信息 关于原来的例外。“
作为记录完整堆栈跟踪的可能解决方法,您可以考虑从Exception
类继承并添加类似堆栈跟踪器属性的内容:
public class StackTraceableException : Exception
{
readonly string stackTrace;
public StackTraceableException() : base() { }
public StackTraceableException(string message, string stackTrace) :
base(message)
{
this.stackTrace = stackTrace;
}
public string StackTrace { get { return stackTrace; } }
}
...并且,继续使用现有的catch
块:
catch (StackTraceableException ex)
{
Console.WriteLine("Exception.StackTrace:");
Console.WriteLine(ex.StackTrace);
}