替换方法体会删除下一行

5
我使用以下代码来替换Roslyn中的方法体:
/* method is instance of MethodDeclarationSyntax */
BlockSyntax newBody = SyntaxFactory.Block(SyntaxFactory.ParseStatement("throw new NotImplementedException();"));
BlockSyntax body = method.Body;
var modifiedMethod = method.ReplaceNode(body, newBody);

但是当我这样做时,方法后面的换行符会被删除,如果在方法后面有一个 #region 或者 #endregion 标签,将会出现错误。
例如:
    #region
    static void RemoveRegions(string str)
    {
        return;
    }
    #endregion

替换body后

    #region
    static void RemoveRegions(string str)
    {
        throw new NotImplementedException();
    }        #endregion    // This cause to compiling error
2个回答

17

原始的BlockSyntax body 包含了一些“尾随Trivia” ,即在右括号后面有一些空格(换行符)。你构造的BlockSyntax newBody 也会包含一个右括号,但是这个右括号不知道它是否应该在它后面有任何空格。

您可以选择以下三种方法之一。我认为第一种选项是最好的选择,但我列出其他选项是为了完整性:

  1. Reuse the trailing trivia from the original node. You can make use of the trailing trivia from the original node by using GetTrailingTrivia and WithTrailingTrivia:

    var originalTrailingTrivia = body.GetTrailingTrivia();
    newBody = newBody.WithTrailingTrivia(originalTrailingTrivia);
    

    In my opinion, this is your best bet. It will preserve the layout of the code by keeping around any trailing trivia (whether it be one blank line, five blank lines, zero blank lines and two spaces, one space and a comment, etc.) and will be more generally suited to other scenarios you haven't dreamed up yet.

  2. Format the new node. Let the built-in Formatter decide how to handle the whitespace by using WithAdditionalAnnotations to add the Formatter.Annotation and perform a Formatter.FormatAsync on the tree containing the newBody:

    newBody = newBody.WithAdditionalAnnotation(Formatter.Annotation)
    // Code that replaces this node back into the document
    var formattedDocument = Formatter.Format(document, Formatter.Annotation);
    

    Note that this will also format the contents of the method. You could format only the close curly brace and tokens around it by adding the Formatter.Annotation directly to the close curly brace itself instead of the entire BlockSyntax and following the same steps. This approach may lay things out in a reasonable way, but it will remove any comments or intentionally strange whitespace attached to the close curly brace.

  3. Add a trailing newline manually. Create a newline manually and add it to newBody with WithTrailingTrivia:

    newBody = newBody.WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed);
    

    This will also remove any comments or intentionally strange whitespace attached to the close curly brace. It also ignores all context and will not honor any user-specified formatting settings that might change the desired layout of method blocks.


我非常感谢你的努力。我不知道为什么它们对我不起作用 :( - Ali Sepehri.Kh
我正在使用 File.WriteAllText(newDoc.FilePath,code); 来保存我的新文档(Document 的实例)。也许问题就出在这里。 - Ali Sepehri.Kh
也许可以尝试使用“newdoc.GetTextAsync().Result.ToString()”打印更新后的代码,看看是否更好。如果是这样,那么问题可能只是你保存方式的问题(你应该请求工作区更新其解决方案)。无论如何,如果你仍然遇到问题,提供额外的代码上下文会很有帮助。 - David Poeschl
GetTextAsync()不起作用,但我在工作区中找不到文档的更新方法。 - Ali Sepehri.Kh

1
要么对新节点进行格式化,要么向其添加SyntaxTrivia

1
Kevin,你能再解释一下吗?我在Roslyn方面还很新。 - Ali Sepehri.Kh
1
对于选项2“添加SyntaxTriva到其中” - 换行符是BlockSyntax上的“尾随trivia”。Trivia是诸如空格、注释等内容。您可以使用GetTrailingTrivia(http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis/Syntax/SyntaxNode.cs,2c8b23967d743711)从原始BlockSyntax中获取其尾随trivia,然后通过WithTrailingTrivia(http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis/Syntax/SyntaxNodeExtensions.cs,c18822a3db364e2b,references)将其添加到newBody中。然后,您将拥有所需的方法体以及原始方法体具有的任何尾随空格。 - David Poeschl
请在另一个更详细的答案中填写此解释。 - David Poeschl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接