Roslyn技术实现:如何在方法调用前后插入语句并保存
在方法调用前后插入语句的Roslyn实现示例
没问题!我帮你调整了代码,用Roslyn的语法节点替换功能就能轻松实现这个需求——核心思路是把原来的方法调用语句,替换成一个包含前置输出语句、原调用语句、后置输出语句的代码块。下面是完整的可运行代码片段:
// 假设你已经有了classitem对应的SyntaxNode(比如ClassDeclarationSyntax) var methodDeclarations = classitem.DescendantNodes().OfType<MethodDeclarationSyntax>(); // 注意:Roslyn的语法节点是不可变的,所以我们需要逐步构建新的根节点 var updatedRoot = classitem.SyntaxTree.GetRoot(); foreach (var memmeth in methodDeclarations) { var varInvocations = memmeth.DescendantNodes().OfType<InvocationExpressionSyntax>(); foreach (var invoc in varInvocations) { // 1. 创建前置的Console.WriteLine语句 var preStatement = SyntaxFactory.ExpressionStatement( SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName("Console"), SyntaxFactory.IdentifierName("WriteLine") ), SyntaxFactory.ArgumentList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument( SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal("Before invocation!")) ) ) ) ) ).WithLeadingTrivia(invoc.GetLeadingTrivia()); // 保留原调用的缩进等格式 // 2. 创建后置的Console.WriteLine语句 var postStatement = SyntaxFactory.ExpressionStatement( SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName("Console"), SyntaxFactory.IdentifierName("WriteLine") ), SyntaxFactory.ArgumentList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument( SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal("After invocation!")) ) ) ) ) ); // 3. 把原调用转换成语句(因为InvocationExpression本身是表达式,需要包裹成ExpressionStatement) var originalStatement = SyntaxFactory.ExpressionStatement(invoc); // 4. 创建包含三条语句的代码块 var newBlock = SyntaxFactory.Block(preStatement, originalStatement, postStatement); // 5. 替换原调用节点为新的代码块,更新根节点 updatedRoot = updatedRoot.ReplaceNode(invoc, newBlock); } } // 6. 把修改后的语法树保存回源文件 var originalPath = classitem.SyntaxTree.FilePath; File.WriteAllText(originalPath, updatedRoot.ToFullString());
几个关键注意点:
- 不可变节点特性:Roslyn的语法节点都是不可变的,所以我们每次替换后都要更新根节点,不能直接修改原来的节点
- 格式保留:用
GetLeadingTrivia()保留原调用的缩进、换行等格式,避免代码排版混乱 - 依赖包:确保你的项目引用了
Microsoft.CodeAnalysis.CSharp和Microsoft.CodeAnalysis.CSharp.WorkspacesNuGet包
内容的提问来源于stack exchange,提问作者Supernova
相关产品推荐
相关产品推荐

