我遇到的问题是,当我使用DocumentEditor.ReplaceNode时,一切正常,但生成的代码难以阅读。
Roslyn - replace node and fix the whitespaces
输出看起来像这样,在同一行上有几个字符串:
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
string test5 = @"test symbols \r\n © @ {} [] <> | / \ $£@!\#¤%&/()=?` hello";
string varTest1 = @"test var hello"; string varTest2 = @"test var hello";
string test1 = @"test string hello";
string test2 = @"test String hello"; string test3 = @"test const hello"; string test4 = @"test readonly hello";
int i = 0;
var i2 = 0;
}
}
}
我可以通过在字符串的末尾添加{System.Environment.NewLine}
并删除所有格式化来获取新行,但代码不会缩进。
我尝试过:
1:
var newVariable = SyntaxFactory.ParseStatement($"string {variable.Identifier.ValueText} = @\"{value + " hello"}\";").WithAdditionalAnnotations(Formatter.Annotation);
newVariable = newVariable.NormalizeWhitespace();
2:
var newVariable = SyntaxFactory.ParseStatement($"string {variable.Identifier.ValueText} = @\"{value + " hello"}\";").WithAdditionalAnnotations(Formatter.Annotation);
3:
var newVariable = SyntaxFactory.ParseStatement($"string {variable.Identifier.ValueText} = @\"{value + " hello"}\";").WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation);
newVariable = newVariable.NormalizeWhitespace();
4:
var newVariable = SyntaxFactory.ParseStatement($"string {variable.Identifier.ValueText} = @\"{value + " hello"}\";");
newVariable = newVariable.NormalizeWhitespace();
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.MSBuild;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Text;
namespace CodeAnalysisApp1
{
class Program
{
static void Main(string[] args)
{
var workspace = new AdhocWorkspace();
var projectId = ProjectId.CreateNewId();
var versionStamp = VersionStamp.Create();
var projectInfo = ProjectInfo.Create(projectId, versionStamp, "NewProject", "projName", LanguageNames.CSharp);
var newProject = workspace.AddProject(projectInfo);
var sourceText = SourceText.From(
@"
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
string test5 = ""test symbols \r\n © @ {} [] <> | / \ $£@!\#¤%&/()=?`"";
var varTest1 = ""test var"";
var varTest2 = ""test var"";
string test1 = ""test string"";
String test2 = ""test String"";
const string test3 = ""test const"";
readonly string test4 = ""test readonly"";
int i = 0;
var i2 = 0;
}
}
}");
var document = workspace.AddDocument(newProject.Id, "NewFile.cs", sourceText);
var syntaxRoot = document.GetSyntaxRootAsync().Result;
var root = (CompilationUnitSyntax)syntaxRoot;
var editor = DocumentEditor.CreateAsync(document).Result;
var localDeclaration = new LocalDeclarationVirtualizationVisitor();
localDeclaration.Visit(root);
var localDeclarations = localDeclaration.LocalDeclarations;
foreach (var localDeclarationStatementSyntax in localDeclarations)
{
foreach (VariableDeclaratorSyntax variable in localDeclarationStatementSyntax.Declaration.Variables)
{
var stringKind = variable.Initializer.Value.Kind();
//Replace string variables
if (stringKind == SyntaxKind.StringLiteralExpression)
{
//Remove " from string
var value = variable.Initializer.Value.ToString().Remove(0, 1);
value = value.Remove(value.Length - 1, 1);
var newVariable = SyntaxFactory.ParseStatement($"string {variable.Identifier.ValueText} = @\"{value + " hello"}\";").WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation);
newVariable = newVariable.NormalizeWhitespace();
editor.ReplaceNode(variable, newVariable);
Console.WriteLine($"Key: {variable.Identifier.Value} Value:{variable.Initializer.Value}");
}
}
}
var newDocument = editor.GetChangedDocument();
var text = newDocument.GetTextAsync().Result.ToString();
}
}
class LocalDeclarationVirtualizationVisitor : CSharpSyntaxRewriter
{
public LocalDeclarationVirtualizationVisitor()
{
LocalDeclarations = new List<LocalDeclarationStatementSyntax>();
}
public List<LocalDeclarationStatementSyntax> LocalDeclarations { get; set; }
public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
{
node = (LocalDeclarationStatementSyntax)base.VisitLocalDeclarationStatement(node);
LocalDeclarations.Add(node);
return node;
}
}
}
答案 0 :(得分:1)
Normalize Whitespace规范化当前对象的空白 - 而不是SyntaxTree中包含的对象。
例如,如果要使用值
调用newVariable上的规范化空格string varTest2 = @"test var hello";
变量声明也在语法树中并不重要 - 重要的是当前上下文。规范化上述语句的空格基本上没有任何意义,因为没有BlockStatements,Declarations或其他会产生缩进的元素。
但是,如果您在包含范围上调用规范化空格,例如方法,则可以获得以下内容:
static void Main(string[] args)
{
string test5 = @"test symbols \r\n © @ {} [] <> | / \ $£@!\#¤%&/()=?` hello";
string varTest1 = @"test var hello";
string varTest2 = @"test var hello";
string test1 = @"test string hello";
string test2 = @"test String hello";
string test3 = @"test const hello";
string test4 = @"test readonly hello";
int i = 0;
var i2 = 0;
}
正如您所看到的,这将为您提供正确的缩进方法。因此,为了获得格式正确的文档,您必须在完成其他所有操作后在SyntaxRoot上调用NormalizeWhitespace:
editor.GetChangedRoot().NormalizeWhitespace().ToFullString()
如果你想保留一些神器(例如你样本中的声明声明之间的附加行),这当然会阻止你保留旧的格式。
如果你想保留这种格式和评论,你可以尝试从原始陈述中复制琐事(或部分琐事):
foreach (var localDeclarationStatementSyntax in localDeclarations)
{
foreach (VariableDeclaratorSyntax variable in localDeclarationStatementSyntax.Declaration.Variables)
{
var stringKind = variable.Initializer.Value.Kind();
//Replace string variables
if (stringKind == SyntaxKind.StringLiteralExpression)
{
//Remove " from string
var value = variable.Initializer.Value.ToString().Remove(0, 1);
value = value.Remove(value.Length - 1, 1);
var newVariable = SyntaxFactory.ParseStatement($"string {variable.Identifier.ValueText} = @\"{value + " hello"}\";").WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation);
newVariable = newVariable.NormalizeWhitespace();
// This is new, copies the trivia (indentations, comments, etc.)
newVariable = newVariable.WithLeadingTrivia(localDeclarationStatementSyntax.GetLeadingTrivia());
newVariable = newVariable.WithTrailingTrivia(localDeclarationStatementSyntax.GetTrailingTrivia());
editor.ReplaceNode(variable, newVariable);
Console.WriteLine($"Key: {variable.Identifier.Value} Value:{variable.Initializer.Value}");
}
}
}