【问题标题】:Exception's Stack trace not complete when throwing in Func抛出 Func 时异常的堆栈跟踪不完整
【发布时间】:2016-12-21 17:54:34
【问题描述】:

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

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

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

【问题讨论】:

  • 想知道这是否适用于为什么不获取完整跟踪的问题。来自 MSDN:“但是,由于优化期间发生的代码转换,StackTrace 属性可能不会报告预期的方法调用数量。”
  • 这是设计使然。如果你捕捉到异常,你是说你想处理它,你如何处理它不应该取决于谁给你打电话。如果不是这种情况,请不要抓住它。出于诊断目的,如果您想要跟踪 catch 块上方的内容,为什么不直接使用您已经在使用的内容:Environment.StackTrace
  • 作为进一步的评论,即使不使用 Func&lt;&gt; 而只是直接调用该方法,您的简单复制也会产生相同的结果。
  • 嗯...感谢您的评论。我认为我的困惑正在发生,因为有时我会在我的错误日志中获得完整的堆栈跟踪,但这可能是由于我记录的位置而不是它们被抛出的位置。谢谢。

标签: c# exception stack-trace


【解决方案1】:

要添加到上面@Dark Falcon 的评论:

这不一定是Func&lt;&gt; 的问题,而是与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);
}

【讨论】:

    猜你喜欢
    • 2021-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多