我正在尝试创建命令构造函数参数的方法。它导航很好,甚至更新树,但序列化文本包含原始参数:
static void Transform(string sourceCode)
{
var tree = CSharpSyntaxTree.ParseText(sourceCode);
var root = (CompilationUnitSyntax)tree.GetRoot();
var @namespace = (NamespaceDeclarationSyntax)
root.ChildNodes().First(n => n.Kind() == SyntaxKind.NamespaceDeclaration);
var @class = (ClassDeclarationSyntax)
@namespace.ChildNodes().First(n => n.Kind() == SyntaxKind.ClassDeclaration);
var constructor = (ConstructorDeclarationSyntax)
@class.ChildNodes().First(n => n.Kind() == SyntaxKind.ConstructorDeclaration);
var parameters = constructor.ParameterList
.ChildNodes()
.Cast<ParameterSyntax>()
.OrderBy(node => ((IdentifierNameSyntax) node.Type).Identifier.ToString())
.Select(node => SyntaxFactory.Parameter(
SyntaxFactory.List<AttributeListSyntax>(),
SyntaxFactory.TokenList(),
SyntaxFactory.ParseTypeName(((IdentifierNameSyntax)node.Type).Identifier.Text),
SyntaxFactory.Identifier(node.Identifier.Text),
null));
var updatedParameterList = SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters));
((SyntaxNode)constructor).ReplaceNode(constructor.ParameterList, updatedParameterList);
Console.WriteLine(root.GetText().ToString());
}
我称之为:
Transform(@"
namespace Test {
class Test {
Test(IParam2 param2, IParam1 param1) { }
}
}");
并希望有
namespace Test {
class Test {
Test(IParam1 param1, IParam2 param2) { }
}
}
但输出仍然是错误顺序的参数。有什么想法吗?
答案 0 :(得分:4)
问题是Roslyn中的所有树都是不可变的。
令人惊讶的是,这条线实际上并没有做任何事情:
((SyntaxNode)constructor).ReplaceNode(constructor.ParameterList, updatedParameterList);
那是因为ReplaceNode()
返回一个全新的语法树,并且不会操纵旧的语法树。
这就是你要找的东西:
static void TransformParameterOrder(string sourceCode)
{
var tree = CSharpSyntaxTree.ParseText(sourceCode);
var root = (CompilationUnitSyntax)tree.GetRoot();
var @namespace = (NamespaceDeclarationSyntax)
root.ChildNodes().First(n => n.Kind() == SyntaxKind.NamespaceDeclaration);
var @class = (ClassDeclarationSyntax)
@namespace.ChildNodes().First(n => n.Kind() == SyntaxKind.ClassDeclaration);
var constructor = (ConstructorDeclarationSyntax)
@class.ChildNodes().First(n => n.Kind() == SyntaxKind.ConstructorDeclaration);
var child = constructor.ParameterList.ChildNodes().Count();
var parameters = constructor.ParameterList
.ChildNodes()
.Cast<ParameterSyntax>()
.OrderBy(node => ((IdentifierNameSyntax)node.Type).Identifier.ToString())
.Select(node => SyntaxFactory.Parameter(
SyntaxFactory.List<AttributeListSyntax>(),
SyntaxFactory.TokenList(),
SyntaxFactory.ParseTypeName(((IdentifierNameSyntax)node.Type).Identifier.Text),
SyntaxFactory.Identifier(node.Identifier.Text),
null))
.Take(2);
var updatedParameterList = SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters));
var newNode = ((SyntaxNode)constructor).ReplaceNode(constructor.ParameterList, updatedParameterList);
//Alternatively you can assign root = root.ReplaceNode...
var newRoot = root.ReplaceNode(constructor.ParameterList, updatedParameterList);
Console.WriteLine(root.GetText().ToString());
Console.WriteLine(newRoot.GetText().ToString());
}