2015-06-22 3 views
0

Я пытаюсь создать метод, который заказывает параметры конструктора. Он переходит хорошо и даже обновляет дерево, но сериализованная текст содержит исходные параметры:Параметры конструктора заказа с Roslyn

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) { } 
    } 
} 

но выход все еще имеют параметры в неправильном порядке. Есть предположения?

ответ

3

Проблема в том, что все деревья в Рослине неизменяемы.

Удивительно, но эта линия не делает ничего:

((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()); 
} 
Смежные вопросы