You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.Workspaces NuGet包

内容的提问来源于stack exchange,提问作者Supernova

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:48:29