在 Roslyn 中获取 ISymbol 信息的通用方法
Generalized Method for Getting ISymbol Information in Roslyn
我正在编写一个文档生成器,它使用 Roslyn 从 C# 源代码中提取信息。作为其中的一部分,我需要获取 ISymbol
各种类型 SyntaxNodes
的信息。但是,似乎没有通用的方法来执行此操作。
假设我想确定某种类型节点的可访问性(例如,private
、protected
、public
)。如果节点包含 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.
您可以创建自己的 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()
方法。
我正在编写一个文档生成器,它使用 Roslyn 从 C# 源代码中提取信息。作为其中的一部分,我需要获取 ISymbol
各种类型 SyntaxNodes
的信息。但是,似乎没有通用的方法来执行此操作。
假设我想确定某种类型节点的可访问性(例如,private
、protected
、public
)。如果节点包含 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.
您可以创建自己的 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()
方法。