首页 > 解决方案 > 在 Roslyn 中获取 ISymbol 信息的通用方法

问题描述

我正在编写一个文档生成器,它使用 Roslyn 从 C# 源代码中提取信息。作为其中的一部分,我需要获取ISymbol各种类型的SyntaxNodes. 但是,似乎没有一种通用的方法可以做到这一点。

假设我想确定某种类型节点的可访问性(例如private,、、、protectedpublicDeclaredAccessibility如果节点包含该属性,则该信息很容易获得。但似乎没有指示给定节点的接口。因此,您必须使用反射来查看是否具有该属性,这可能在计算上很昂贵,或者确切地知道您正在处理的节点类型,以便您可以将其转换为正确的类型。

这是一个基于相关情况的示例,涉及确定 a 的可访问性const

public const string Dummy = "abc";

当我遍历语法树并使用相应的语义模型来提取可访问性信息时,我最终会这样做:

SyntaxNode nodeToTest = null;

switch( syntaxNode )
{
    case FieldDeclarationSyntax fieldDecNode:
        // all the fields expressed in a field declaration share the same
        // modifiers (e.g., public, static, const) and type; they're basically
        // all from the same statement/line of code
        nodeToTest = fieldDecNode.Declaration.Variables.FirstOrDefault();
        break;

    default:
        nodeToTest = syntaxNode;
        break;
}

var nodeInfo = syntaxTree.Model.GetDeclaredSymbol( nodeToTest );

这行得通,如果这是最不坏的方法,我会接受它(并在遇到其他怪癖时扩展它)。但这感觉很笨拙,我想使用更好/更灵活的方法。

标签: c#roslyn

解决方案


你考虑过使用CSharpSyntaxWalker吗?

表示一个 CSharpSyntaxVisitor,它下降整个 CSharpSyntaxNode 图,以深度优先的顺序访问每个 CSharpSyntaxNode 及其子 SyntaxNodes 和 SyntaxTokens。

https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.csharp.csharpsyntaxwalker?view=roslyn-dotnet

您可以创建自己的 walker 类,该类继承自CSharpSyntaxWalker该类并覆盖SyntaxNode您关注的每个子类型的访问函数。这意味着节点的类型将在函数中已知。对于您的示例,您将覆盖该VisitFieldDeclaration方法。SyntaxNode文档链接显示了您可以覆盖的每种访问者类型的方法。

internal class TestWalker : CSharpSyntaxWalker
{
    private readonly SemanticModel _model;

    public TestWalker(SemanticModel model)
    {
        _model = model;
    }

    public override void VisitFieldDeclaration(FieldDeclarationSyntax node)
    {
        // do your const field accessibility analysis here
    }

    // override any other syntax visitors here
}

您可以将所需的任何其他实现细节添加到该类中。当您需要进行分析时,实例化您的步行器并调用您想要开始步行的Visit()方法。SyntaxNode


推荐阅读