在 Roslyn 中获取 ISymbol 信息的通用方法

Generalized Method for Getting ISymbol Information in Roslyn

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

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

这是一个基于相关情况的示例,涉及确定 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 );

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

您是否考虑过使用 CSharpSyntaxWalker

Represents a CSharpSyntaxVisitor that descends an entire CSharpSyntaxNode graph visiting each CSharpSyntaxNode and its child SyntaxNodes and SyntaxTokens in depth-first order.

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

您可以创建自己的 walker class,它继承自 CSharpSyntaxWalker class,并为您关注的 SyntaxNode 的每个子类型覆盖访问函数。这意味着节点的类型在函数中是已知的。对于您的示例,您将覆盖 VisitFieldDeclaration 方法。文档 link 显示了您可以覆盖的每种 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
}

您可以向 class 添加您需要的任何其他实施细节。当您需要进行分析时,实例化您的助行器并在您要开始行走的 SyntaxNode 上调用 Visit() 方法。