编辑
2025-10-15
C#
00

目录

环境准备
使用Factory方法创建语法树
基本概念
实战示例:转换using语句
修改现有语法树
总结

.NET Compiler Platform (Roslyn) SDK提供了强大的语法分析和转换功能。本文将介绍如何使用Roslyn进行代码转换,包括两种主要方法:

  • 使用Factory方法创建和修改语法树
  • 使用SyntaxRewriter进行批量转换

环境准备

首先需要安装Visual Studio和.NET Compiler Platform SDK:

  1. 打开Visual Studio Installer
  2. 选择"修改"
  3. 可以通过以下两种方式之一安装:
    • 工作负载视图:选择"Visual Studio扩展开发"工作负载,然后在可选组件中勾选".NET Compiler Platform SDK"
    • 单个组件视图:直接勾选".NET Compiler Platform SDK"

image.png

使用Factory方法创建语法树

基本概念

Roslyn的一个重要特性是不可变性(Immutability)。这意味着:

  • 语法树创建后不能修改
  • 需要通过创建新的树来实现转换
  • 保证了并发安全性

实战示例:转换using语句

C#
using System; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace AppRoslyn { internal class Program { static void Main(string[] args) { // 添加静态方法引用或扩展方法 NameSyntax name = SyntaxFactory.IdentifierName("System"); // 创建限定名 name = SyntaxFactory.QualifiedName(name, SyntaxFactory.IdentifierName("Collections")); // System.Collections // 继续构建 name = SyntaxFactory.QualifiedName(name, SyntaxFactory.IdentifierName("Generic")); // System.Collections.Generic // 输出结果 Console.WriteLine(name.ToString()); // 额外演示:创建更复杂的命名空间 NameSyntax complexName = SyntaxFactory.QualifiedName( SyntaxFactory.QualifiedName( SyntaxFactory.QualifiedName( SyntaxFactory.IdentifierName("Microsoft"), SyntaxFactory.IdentifierName("CodeAnalysis") ), SyntaxFactory.IdentifierName("CSharp") ), SyntaxFactory.IdentifierName("Syntax") ); Console.WriteLine(complexName.ToString()); Console.ReadKey(); } } }

修改现有语法树

C#
using System; using System.Collections.Generic; using System.Reflection; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Emit; using System.IO; namespace AppRoslyn { internal class Program { // 获取更全面的系统程序集引用 private static List<MetadataReference> GetComprehensiveReferences() { var references = new List<MetadataReference>(); // 获取当前应用程序域中已加载的程序集 var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); // 添加常用的系统程序集 var systemAssemblyNames = new[] { "System.Runtime", "System.Core", "System.Linq", "System.Collections", "System.Console", "netstandard" }; // 尝试加载系统程序集引用 foreach (var assemblyName in systemAssemblyNames) { try { var assembly = Assembly.Load(assemblyName); if (!string.IsNullOrEmpty(assembly.Location)) { references.Add(MetadataReference.CreateFromFile(assembly.Location)); } } catch (Exception) { // 静默处理加载失败的程序集 } } // 添加已加载程序集的引用 foreach (var assembly in loadedAssemblies) { try { if (!string.IsNullOrEmpty(assembly.Location) && !references.Any(r => r.Display == assembly.Location)) { references.Add(MetadataReference.CreateFromFile(assembly.Location)); } } catch (Exception) { // 静默处理可能的异常 } } return references; } public static SyntaxTree RefactorDeprecatedMethods(string sourceCode) { // 解析原始代码 SyntaxTree originalTree = CSharpSyntaxTree.ParseText(sourceCode); CompilationUnitSyntax root = (CompilationUnitSyntax)originalTree.GetRoot(); // 自定义重构规则:将过时的方法调用替换为新的方法 var refactoredRoot = root.ReplaceNodes( root.DescendantNodes().OfType<InvocationExpressionSyntax>(), (originalNode, _) => { // 示例:将 OldMethod() 替换为 NewMethod() if (originalNode.Expression is IdentifierNameSyntax identifierName && identifierName.Identifier.Text == "OldMethod") { return SyntaxFactory.InvocationExpression( SyntaxFactory.IdentifierName("NewMethod") ).WithTriviaFrom(originalNode); } return originalNode; } ); return CSharpSyntaxTree.Create((CompilationUnitSyntax)refactoredRoot); } public static object DynamicCompileAndExecute(string sourceCode) { // 重构代码 SyntaxTree refactoredTree = RefactorDeprecatedMethods(sourceCode); string refactoredCode = refactoredTree.GetRoot().ToFullString(); // 准备引用 - 使用更全面的引用方法 var references = GetComprehensiveReferences(); // 创建编译选项 var compilationOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication) .WithOptimizationLevel(OptimizationLevel.Release); // 创建编译单元 var compilation = CSharpCompilation.Create("DynamicAssembly") .AddReferences(references) .AddSyntaxTrees(CSharpSyntaxTree.ParseText(refactoredCode)) .WithOptions(compilationOptions); // 使用内存流编译 using (var ms = new MemoryStream()) { // 执行编译 EmitResult result = compilation.Emit(ms); // 处理编译错误 if (!result.Success) { var failures = result.Diagnostics.Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error); foreach (var diagnostic in failures) { Console.WriteLine($"{diagnostic.Id}: {diagnostic.GetMessage()}"); Console.WriteLine($"{diagnostic.Location}"); } throw new Exception("出错了"); } // 加载程序集 ms.Seek(0, SeekOrigin.Begin); var assembly = Assembly.Load(ms.ToArray()); // 查找 Main 方法 var entryPoint = assembly.EntryPoint; if (entryPoint == null) { throw new Exception("No entry point found"); } // 创建类型实例(如果是静态方法,传 null) object instance = entryPoint.IsStatic ? null : Activator.CreateInstance(entryPoint.DeclaringType); // 调用入口方法 return entryPoint.Invoke(instance, null); } } public static object DynamicCompileAndExecuteWithoutModification(string sourceCode) { // 准备引用 - 使用更全面的引用方法 var references = GetComprehensiveReferences(); // 创建编译选项 var compilationOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication) .WithOptimizationLevel(OptimizationLevel.Release); // 创建编译单元 var compilation = CSharpCompilation.Create("DynamicAssembly") .AddReferences(references) .AddSyntaxTrees(CSharpSyntaxTree.ParseText(sourceCode)) .WithOptions(compilationOptions); // 使用内存流编译 using (var ms = new MemoryStream()) { // 执行编译 EmitResult result = compilation.Emit(ms); // 处理编译错误 if (!result.Success) { var failures = result.Diagnostics.Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error); foreach (var diagnostic in failures) { Console.WriteLine($"{diagnostic.Id}: {diagnostic.GetMessage()}"); Console.WriteLine($"{diagnostic.Location}"); } throw new Exception("出错了!"); } // 加载程序集 ms.Seek(0, SeekOrigin.Begin); var assembly = Assembly.Load(ms.ToArray()); // 查找 Main 方法 var entryPoint = assembly.EntryPoint; if (entryPoint == null) { throw new Exception("No entry point found"); } // 创建类型实例(如果是静态方法,传 null) object instance = entryPoint.IsStatic ? null : Activator.CreateInstance(entryPoint.DeclaringType); // 调用入口方法 return entryPoint.Invoke(instance, null); } } // 主方法 public static void Main(string[] args) { string sourceCode = @" using System; using System.Linq; class Program { static void Main() { OldMethod(); Console.WriteLine(""旧方法执行完成""); int[] numbers = { 1, 2, 3, 4, 5 }; var evenNumbers = numbers.Where(n => n % 2 == 0).ToArray(); Console.WriteLine(""Even numbers: "" + string.Join("", "", evenNumbers)); } static void OldMethod() { Console.WriteLine(""旧方法执行""); } static void NewMethod() { Console.WriteLine(""新方法执行""); } }"; try { // 不修改 OldMethod 的动态编译并执行 DynamicCompileAndExecuteWithoutModification(sourceCode); DynamicCompileAndExecute(sourceCode); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); Console.WriteLine(ex.StackTrace); } Console.ReadKey(); } } }

image.png

总结

Roslyn提供了强大而灵活的代码转换能力。通过Factory方法和SyntaxRewriter,我们可以实现从简单的语法替换到复杂的代码重构。理解不可变性原则和正确使用语义模型是成功实现代码转换的关键。

本文作者:技术老小子

本文链接:

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