投掷Func时,异常的堆栈跟踪未完成

时间:2016-12-21 17:54:34

标签: c# exception stack-trace

我遇到一个问题,当通过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

这导致我出现问题的原因是,在实际代码中,这是从几个不同的地方调用并传入变量和其他类似的东西,当它出错时我记录包括堆栈跟踪在内的异常。我希望能够确切地看到导致错误的代码路径,并且最好不必更改我的记录方式。

所以问题是为什么我没有获得完整的堆栈跟踪,我能做些什么来让它给我一个完整的堆栈跟踪?

1 个答案:

答案 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);
}