Roslyn - 如何在另一个语句之前和之后添加语句

时间:2018-03-23 12:23:40

标签: c# .net roslyn

我有以下代码来检测方法调用。我想在源代码中添加一个简单的语句(例如,Console.WriteLine(" Test");)在该调用语句之前和之后,并将其保存回源文件。任何代码片段或示例都说明了如何做到这一点?

var methodDeclarations = classitem.DescendantNodes().OfType<MethodDeclarationSyntax>();
foreach (var memmeth in methodDeclarations)
{

    var varInvocations = memmeth.DescendantNodes().OfType<InvocationExpressionSyntax>();
    foreach (InvocationExpressionSyntax invoc in varInvocations)
    {
             // insert new statement before and after the invocation

1 个答案:

答案 0 :(得分:1)

您正在尝试将语句与表达式混合。

如果我写

this.Test();

在我的代码中,它是ExpressionStatement中InvocationExpression中的SimpleExpressionStatement。

Statement基本上是代表单行代码的元素,在我们的示例中是this.Test();,可能类似于return;扔;等

因此,如果您希望在表达式之前或之后插入语句,则必须在contains语句之前或之后插入它。

但是,这可能会产生问题,因为您可以在同一个Statement中使用多个表达式,例如

if(Test() && Test2()){

}

因此,为了在方法调用之前或之后插入新语句,您只需找到最近的Statement并在所述语句之前或之后插入它,例如:

var statements = new List<StatementSyntax>();
var methodDeclarations = root.DescendantNodes().OfType<MethodDeclarationSyntax>();
foreach (var memmeth in methodDeclarations)
{
    var varInvocations = memmeth.DescendantNodes().OfType<InvocationExpressionSyntax>();
    foreach (InvocationExpressionSyntax invoc in varInvocations)
    {
        // Find the relevant node
        var statement = invoc.Ancestors().OfType<StatementSyntax>().FirstOrDefault();
        statements.Add(statement);
    }
}
// Track the nodes so you can change it in the tree even after modifying it
root = root.TrackNodes(statements.Distinct());
foreach(var statement in statements)
{
    var currentStatement = root.GetCurrentNode(statement);
    root = root.InsertNodesAfter(currentStatement,            
        new[] { SyntaxFactory.ExpressionStatement(
                    SyntaxFactory.InvocationExpression(
                        SyntaxFactory.MemberAccessExpression(
                            SyntaxKind.SimpleMemberAccessExpression, 
                            SyntaxFactory.IdentifierName("Console"), 
                            SyntaxFactory.IdentifierName("WriteLine"))
                        ))});
    currentStatement = root.GetCurrentNode(statement);
    root = root.InsertNodesBefore(currentStatement,
        new[] { SyntaxFactory.ExpressionStatement(
            SyntaxFactory.InvocationExpression(
                SyntaxFactory.MemberAccessExpression(
                    SyntaxKind.SimpleMemberAccessExpression,
                    SyntaxFactory.IdentifierName("Console"),
                    SyntaxFactory.IdentifierName("WriteLine"))
                ))});
}