【问题标题】:Parsing C# Conditional Compilation statements in roslyn在 roslyn 中解析 C# 条件编译语句
【发布时间】:2016-12-01 13:23:12
【问题描述】:

如何使用 Roslyn 解析 C# 条件编译语句。

在下面的代码中,我希望Roslyn给出条件编译语句节点。

public abstract class TestClass
{
    public int Get()
    {
    #if DEBUG
        return 1;
    #else
        return 2;
    #endif
    }
}

我没有在 SyntaxTree 中获得条件编译节点,它也不是 } 的 LeadingTrivia 或 { 的 TrailingTrivia 的一部分

我在} 的LeadingTrivia 中得到的是"\t\t#endif\r\n\t\t"{ 的TrailingTrivia 是"\r\n",这不是完整的条件编译语句。

有人能指出正确的方向吗?

【问题讨论】:

  • 如果您愿意考虑非 Roslyn 解决方案,我可以描述一个过程非常简单的解决方案。
  • @ira-baxter 它必须是 roslyn 特定的

标签: c# parsing roslyn conditional-compilation


【解决方案1】:

如果您通过访问者 (CSharpSyntaxRewriter\Walker) 解析节点,则需要覆盖:

public override SyntaxNode VisitIfDirectiveTrivia(IfDirectiveTriviaSyntax node)
{
}

public override SyntaxNode VisitElseDirectiveTrivia(ElseDirectiveTriviaSyntax node)
{
}

public override SyntaxNode VisitEndIfDirectiveTrivia(EndIfDirectiveTriviaSyntax node)
{
}

如果您不想通过访问者获得此信息,您可以这样做:

node.DescendantNodesAndSelf().OfType<ConditionalDirectiveTriviaSyntax>();

您可以查看here 以了解 Roslyn 为您的条件生成了什么。

更新

我查了一下,这里确实有点复杂,因为它当然不是Node。该节点只是return 2,或者如果你写#define DEBUG它的return 1

所以,如果你在方法中有条件指令,你可以这样做:

// First get the relevant method (or any other parent block depending in the case)
var method = root.DescendantNodes().OfType<MethodDeclarationSyntax>().First();

// Then, you can write method similar to this
static SyntaxTrivia GetConditionalDirectiveTrivia(SyntaxNode node, SyntaxKind kind)
{
    foreach (SyntaxNode syntaxNode in node.DescendantNodes())
    {
        var trivia = syntaxNode.GetLeadingTrivia().FirstOrDefault(t => t.Kind() == kind);
        if (trivia != default(SyntaxTrivia))
            return trivia;
        GetConditionalDirectiveTrivia(syntaxNode, kind);
    }
    return default(SyntaxTrivia);
}

然后这样称呼它:

GetConditionalDirectiveTrivia(method, SyntaxKind.IfDirectiveTrivia);

没有 Kind 你可以通过更多方式找到它,但我认为它已经足够好了。

请注意,这只是一个示例。我在这里只返回第一个琐事。

在您的真实代码中,您可以编写更优雅的解决方案(甚至可能是扩展方法)来获取例如AllTriviaOfKind 或其他符合您要求的东西。 此外,如果琐事本身对您无用,您可以返回令牌琐事或父节点,无论您想要什么\需要。

希望对你有所帮助。

【讨论】:

  • 我没有使用访问者,所以我尝试在 Method 节点上调用 DescendantNodesAndSelf,但我没有在列表中看到 ConditionalDirectiveTriviaSyntax 而是有一个 BlockSyntax(这太通用了)
  • @adeel41 BlockSyntax 是所有方法体的父级。在此块中,您将找到语句,然后您将找到所需的内容。因此,如果您的原始节点是MethodDeclerationSyntax,您需要深入了解才能找到您想要的。
  • @adeel41 我现在用手机写信。我会尽快更新我的答案,并告诉你具体的操作方法(如果你需要的话)
  • 这是我从 thae Block node ` [0]: SyntaxNodeOrToken Block { #if DEBUG return 1; #否则返回2; #endif } [1]: SyntaxNodeOrToken OpenBraceToken { [2]: SyntaxNodeOrToken ReturnStatement return 2; [3]: SyntaxNodeOrToken ReturnKeyword 返回 [4]: SyntaxNodeOrToken NumericLiteralExpression 2 [5]: SyntaxNodeOrToken NumericLiteralToken 2 [6]: SyntaxNodeOrToken SemicolonToken ; [7]: 语法节点或令牌 CloseBraceToken }`
  • @adeel41 等我回到办公室我会更新答案
【解决方案2】:

我没有在 SyntaxTree 中获得条件编译节点,它也不是 } 的 LeadingTrivia 或 { 的 TrailingTrivia 的一部分

其实就是在return 2;中的return关键字的LeadingTrivia中。 return 的主要琐事是:

  • IfDirectiveTrivia (#if DEBUG)
  • DisableTextTrivia (return 1;)
  • ElseDirectiveTrivia (#else)

【讨论】:

  • 感谢您提供一些有关如何查找该信息的信息,但不确定我是否会这样做,因为看起来我需要解析很多内容。
猜你喜欢
  • 1970-01-01
  • 2012-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多