我们如何轻松找到代码中的哪一行导致运行时异常?

时间:2014-04-15 20:20:19

标签: c# roslyn

考虑以下分析器:

public void AnalyzeNode(SyntaxNode node, SemanticModel semanticModel, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken)
{
    var throwStatement = node as ThrowStatementSyntax;

    var isObjectCreationExpression = throwStatement.Expression is ObjectCreationExpressionSyntax;
    var obj = throwStatement.Expression as ObjectCreationExpressionSyntax;

    var isCorrectTypeOfExpression = (obj.Type as IdentifierNameSyntax).Identifier.Text == typeof(ArgumentException).Name;
}

SyntaxKind.ThrowStatement作为兴趣点。

obj如果在null表单中未正确声明抛出的异常,则应为new Exception(),而应显示为throw e其中e为先前宣布的例外。

这会在NullReferenceException之后立即调出obj.Type

有问题的例子:

static void Method1()
{
    throw new ArgumentException();
}

static void Method2(ArgumentException e)
{
    throw e;
}

第一个throw会很好地通过分析器,但第二个obj会导致nullObjectCreationExpressionSyntax,因为它不是1类型。

在沙盒Visual Studio环境中,这将显示为信息消息:

  

用户诊断分析器&#39; FormattingFixes.EmptyArgumentException.ArgumentExceptionAnalyzer&#39;在消息&#39;对象引用未设置为对象实例的情况下抛出异常。&#39;。

在这个简短的样本中,很容易分辨问题所在,但在一个不那么人为的例子中,它将更难被发现。行和列都是{{1}},没有帮助。

传统&#34;编程时,您的环境会自动显示抛出运行时异常的位置以及该时间点的值。我可以在我的代码中的某个地方放置一个随机断点,每次点击时查看所有值,并尝试从那里推断出它,但是一旦节点数远远高于这些值,这就不能很好地扩展。 2。

我们如何轻松找到代码中的哪一行导致运行时异常?

2 个答案:

答案 0 :(得分:5)

所以你应该还是休息一下,但是如果你没有要检查的东西:

转到“调试”菜单下,然后选择“例外”。您将看到“Thrown”或“User-unhandled”列。使用Find查找NullReferenceException,并选中“thrown”复选框。一旦抛出NullReferenceException,这将导致VS中断。如果你想要非常积极,你可以告诉它打破所有例外。

如果仍无效,请转到工具&gt;选项,调试,常规和清除“只是我的代码”。这里需要注意的是,这会破坏所有异常,包括VS中甚至不是你的错误的部分。 (可悲的是,我们在很多不同的地方都抛出了很多例外。)

如果您愿意,请随意file a bug,以便我们可以将消息包括堆栈跟踪和行/列,以便更容易调试。

因为我在这里:你的代码确实

var isCorrectTypeOfExpression = (obj.Type as IdentifierNameSyntax).Identifier.Text == typeof(ArgumentException).Name;

注意语法检查 - 如果我写throw new System.ArgumentException()会怎样?正确的方法是获取语义模型并绑定ObjectCreationExpression以确定实际类型是什么。 (如果你在意的话,这也意味着你在别名的情况下工作。)

答案 1 :(得分:-1)

使用以下步骤获取引发异常的行号。

  1. 获取异常的StackTrace。
  2. 获取堆栈的顶部框架。
  3. 从堆栈框架中获取行号。
  4. 以下是代码段。

    try
    {
    
        //TODO
        throw new Exception();
    }
    catch (Exception ex)
    {
        var stacktrace = new StackTrace(ex, true);
        var frame = st.GetFrame(0);
        var filelinenumber = frame.GetFileLineNumber();
    }