编辑
2025-10-15
C#
00

目录

核心概念
Compilation(编译单元)
SemanticModel(语义模型)
实战示例
分析命名空间
分析类型信息
方法查找
总结

Roslyn 提供了两个主要的 API 来分析代码:语法 API(Syntax API)和语义 API(Semantic API)。其中,语法 API 用于分析代码的结构,而语义 API 则专注于分析代码的语义和含义。本文将重点介绍与语义分析相关的 API 使用方法。

核心概念

Compilation(编译单元)

Compilation代表编译器视角下的一个完整项目,包含:

  • 源代码文件
  • 程序集引用
  • 编译选项
C#
// 创建编译单元 var compilation = CSharpCompilation.Create("HelloWorld") .AddReferences(MetadataReference.CreateFromFile( typeof(string).Assembly.Location)) .AddSyntaxTrees(syntaxTree);

SemanticModel(语义模型)

SemanticModel提供了类似IDE智能提示的功能:

  • 查询作用域内的名称
  • 查询可访问的成员
  • 分析表达式引用的对象
C#
// 获取语义模型 SemanticModel model = compilation.GetSemanticModel(syntaxTree);

实战示例

分析命名空间

C#
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; namespace AppRoslyn { internal class Program { static void Main(string[] args) { // 示例程序 const string code = @" using System; namespace Demo { class Program { static void Main() { Console.WriteLine(""Hello""); } } }"; // 解析语法树 SyntaxTree tree = CSharpSyntaxTree.ParseText(code); var root = tree.GetCompilationUnitRoot(); // 创建编译单元和语义模型 var compilation = CSharpCompilation.Create("Demo") .AddReferences(MetadataReference.CreateFromFile(typeof(string).Assembly.Location)) .AddSyntaxTrees(tree); var model = compilation.GetSemanticModel(tree); // 获取using System的符号信息 var firstUsing = root.Usings[0]; var systemName = firstUsing.Name; var symbolInfo = model.GetSymbolInfo(systemName); // 分析System命名空间 var systemSymbol = (INamespaceSymbol)symbolInfo.Symbol; foreach (var ns in systemSymbol.GetNamespaceMembers()) { Console.WriteLine(ns); // 输出子命名空间 } Console.ReadKey(); } } }

image.png

分析类型信息

C#
// 查找字符串字面量 var stringLiteral = root.DescendantNodes() .OfType<LiteralExpressionSyntax>() .First(); // 获取类型信息 TypeInfo typeInfo = model.GetTypeInfo(stringLiteral); var stringType = (INamedTypeSymbol)typeInfo.Type; // 查询string类型的所有公共方法 var publicMethods = from method in stringType.GetMembers().OfType<IMethodSymbol>() where method.DeclaredAccessibility == Accessibility.Public select method.Name; // 输出方法名 foreach(var name in publicMethods.Distinct()) { Console.WriteLine(name); }

image.png

方法查找

C#
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; namespace AppRoslyn { internal class Program { static void Main(string[] args) { const string code = @" using System; namespace Demo { class Program { static void Main() { Console.WriteLine(""Hello""); } } }"; // 解析语法树 SyntaxTree tree = CSharpSyntaxTree.ParseText(code); var root = tree.GetCompilationUnitRoot(); // 创建编译单元和语义模型 var compilation = CSharpCompilation.Create("Demo") .AddReferences(MetadataReference.CreateFromFile(typeof(string).Assembly.Location)) .AddSyntaxTrees(tree); var model = compilation.GetSemanticModel(tree); // 专门查找 Main 方法 FindMainMethod(root, model); Console.ReadLine(); } static void FindMainMethod(CompilationUnitSyntax root, SemanticModel model) { // 查找所有方法声明 var methodDeclarations = root.DescendantNodes() .OfType<MethodDeclarationSyntax>(); // 筛选 Main 方法 var mainMethods = methodDeclarations .Where(method => method.Identifier.Text == "Main" && method.Modifiers.Any(SyntaxKind.StaticKeyword) ); foreach (var mainMethod in mainMethods) { var methodSymbol = model.GetDeclaredSymbol(mainMethod); if (methodSymbol != null) { Console.WriteLine("找到 Main 方法:"); Console.WriteLine($"方法名: {mainMethod.Identifier}"); Console.WriteLine($"所在类型: {methodSymbol.ContainingType.Name}"); Console.WriteLine($"返回类型: {methodSymbol.ReturnType}"); Console.WriteLine("方法体:"); Console.WriteLine(mainMethod.Body?.ToFullString() ?? "空方法体"); } } if (!mainMethods.Any()) { Console.WriteLine("未找到 Main 方法"); } } } }

image.png

总结

Roslyn的语义分析API提供了强大的代码分析能力:

  • 可以分析类型信息
  • 可以解析符号引用
  • 可以查询成员信息
  • 支持完整的程序理解

通过合理使用这些API,我们可以构建代码分析工具、重构工具等高级开发辅助工具。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!