2 .netcore Roslyn 动态编译 语法分析

本文介绍如何在Visual Studio中使用.NET Compiler Platform SDK和Roslyn API解析C#代码的语法树,包括安装必要的软件包、理解语法树的构成、遍历语法节点以及使用语法查看器进行更深入的代码分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:
https://docs.microsoft.com/zh-cn/dotnet/csharp/roslyn-sdk/get-started/syntax-analysis

安装 .NET Compiler Platform SDK

安装 .NET Compiler Platform SDK 我们可以在Visual Studio查看语法树
执行如下步骤安装 .NET Compiler Platform SDK
运行“Visual Studio 安装程序”
选择“修改”
检查“Visual Studio 扩展开发”工作负荷 。
在摘要树中打开“Visual Studio 扩展开发”节点 。
选中“.NET Compiler Platform SDK”框 。 将在可选组件最下面找到它。

安装包

使用Roslyn前先安装包 Microsoft.CodeAnalysis.CSharp

了解语法树

语法树由生成项目时或开发人员按 F5 时所运行的分析程序生成。
语法树的四个主要构建基块为:
Microsoft.CodeAnalysis.SyntaxTree 类:
代表整个分析树。 SyntaxTree 是一种带有语言特定派生类的抽象类。 使用 Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree类对 C# 的文本进行分析。
Microsoft.CodeAnalysis.SyntaxNode 类:
表示语法节点,如声明、语句、子句和表达式等语法
Microsoft.CodeAnalysis.SyntaxToken 结构:
表示语法标志,它代表独立的关键词、标识符、运算符或标点。
Microsoft.CodeAnalysis.SyntaxTrivia 结构:
它代表语法上不重要的信息,例如标记、预处理指令和注释之间的空格。

在 Visual Studio 中,选择“视图” > “其他窗口” > “语法可视化工具”查看代码语法
SyntaxNode:蓝色 | SyntaxToken:绿色 | SyntaxTrivia:红色

遍历语法节点

        static void Main(string[] args)
        {
            const string programText =
@"using System;
using System.Collections;
using System.Linq;
using System.Text;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(""Hello, World!"");
        }
    }
}";
            SyntaxTree tree = CSharpSyntaxTree.ParseText(programText);
            // 获取根语法节点
            CompilationUnitSyntax root = tree.GetCompilationUnitRoot();

            // 语法的类型,当前为 CompilationUnit 类型
            Console.WriteLine($"The tree is a {root.Kind()} node.");
            // 遍历语法使用的 Using
            foreach (UsingDirectiveSyntax element in root.Usings)
                Console.WriteLine($"\t{element.Name}");

            // 遍历根语法节点的成员,返回子语法节点
            MemberDeclarationSyntax firstMember = root.Members[0];
            // 查看语法节点的类型
            Console.WriteLine($"The first member is a {firstMember.Kind()}.");
            // 其实该子语法节点是个 命名空间语法节点,所以强制转换
            var helloWorldDeclaration = (NamespaceDeclarationSyntax)firstMember;

            // 获取子语法节点
            var programDeclaration = (ClassDeclarationSyntax)helloWorldDeclaration.Members[0];
            // Identifier 是语法标志,包含类的名称
            Console.WriteLine($"{programDeclaration.Identifier} class.");

            // 获取子语法节点
            var mainDeclaration = (MethodDeclarationSyntax)programDeclaration.Members[0];

            // 返回类型
            Console.WriteLine($"The return type is {mainDeclaration.ReturnType}.");
            
            // 遍历参数语法节点
            foreach (ParameterSyntax item in mainDeclaration.ParameterList.Parameters)
                Console.WriteLine($"The type of the {item.Identifier} parameter is {item.Type}.");

            var argsParameter = mainDeclaration.ParameterList.Parameters[0];

            Console.ReadKey();
        }

查询方法

除了遍历树,还可以使用 Microsoft.CodeAnalysis.SyntaxNode 上定义的查询方法来探索语法树

SyntaxTree tree = CSharpSyntaxTree.ParseText(programText);
// 获取根语法节点
CompilationUnitSyntax root = tree.GetCompilationUnitRoot();

// DescendantNodes 为获取所有子语法节点(Descendant:后代)
var firstParameters = from methodDeclaration in root.DescendantNodes()
                                        .OfType<MethodDeclarationSyntax>()
                      where methodDeclaration.Identifier.ValueText == "Main"
                      select methodDeclaration.ParameterList.Parameters.First();

var argsParameter2 = firstParameters.Single();

Console.WriteLine(argsParameter2.ToFullString());

语法查看器(CSharpSyntaxWalker)

查看器接收一个语法节点,并遍历该节点和其子节点
定义查看器

public class UsingCollector : CSharpSyntaxWalker
{
    public ICollection<UsingDirectiveSyntax> Usings { get; } = new List<UsingDirectiveSyntax>();

    public override void VisitUsingDirective(UsingDirectiveSyntax node)
    {
        if (node.Name.ToString() == "System" || node.Name.ToString().StartsWith("System."))
        {
            this.Usings.Add(node);
        }
    }
}

使用查看器遍历语法数

SyntaxTree tree = CSharpSyntaxTree.ParseText(programText);
// 获取根语法节点
CompilationUnitSyntax root = tree.GetCompilationUnitRoot();

var collector = new UsingCollector();
collector.Visit(root);
foreach (var directive in collector.Usings)
{
    Console.WriteLine(directive.Name);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值