如何通过添加和删除从旧根检索到的节点来创建新根?

我正在创建一个修改代码修复:

if(obj is MyClass) { var castedObj = obj as MyClass; } 

进入这个:

 var castedObj = obj as MyClass; if(castedObj != null) { } 

这意味着我必须做三件事:

  • 更改if语句中的条件。
  • 将转换移到if语句的正上方。
  • 删除正文中的语句。

到目前为止,我所有的尝试都让我陷入困境,最多可以使这两件事情发挥作用。

我相信会出现此问题,因为您在同一级别上基本上有2个语法节点。 因此,对其中一个进行更改会使另一个的位置无效。 或类似的东西。 简而言之:我要么设法在if语句之外复制变量赋值,要么我设法更改条件+删除变量赋值。 绝不是全部3。

我该如何解决这个问题?

为了更好地衡量,这是我的代码,它改变了条件并删除了赋值:

 var newIfStatement = ifStatement.RemoveNode( variableDeclaration, SyntaxRemoveOptions.KeepExteriorTrivia); newIfStatement = newIfStatement.ReplaceNode(newIfStatement.Condition, newCondition); var ifParent = ifStatement.Parent; var newParent = ifParent.ReplaceNode(ifStatement, newIfStatement); newParent = newParent.InsertNodesBefore( newIfStatement, new[] { variableDeclaration }) .WithAdditionalAnnotations(Formatter.Annotation); var newRoot = root.ReplaceNode(ifParent, newParent); 

你看过DocumentEditor类了吗? 在处理修改语法时非常有用,尤其是当应用于树的更改可能导致失效问题时。 这些操作与您已经定义的操作几乎相同,只需使用DocumentEditor方法,看看是否有帮助。 我无法validation这是否解决了您的问题ATM,但我认为它曾经解决了我过去的类似问题。 如果可以的话,我稍后会测试一下。

像这样的东西会这样做:

 var editor = await DocumentEditor.CreateAsync(document); editor.RemoveNode(variableDeclaration); editor.ReplaceNode(ifStatement.Condition, newCondition); editor.InsertBefore(ifStatement, new[] { variableDeclaration.WithAdditionalAnnotations(Formatter.Annotation) }); var newDocument = editor.GetChangedDocument(); 

我已经设法通过以下方式做了一些非常相似的事情。 我提取while条件并在while之前移动它并用新节点替换条件。 在一段时间内,我添加了一个新的声明。 在您的情况下,您将从正文中删除所需的语句,而不是添加语句。

从…开始

 Refactor(BlockSyntax oldBody) 

第1步:我首先访问并标记我想要更改的节点,同时生成新节点,但不要添加新节点。

第2步:跟踪标记的节点并替换为新节点。

 class WhileConditionRefactoringVisitor : CSharpSyntaxRewriter { private static int CONDITION_COUNTER = 0; private static string CONDITION_VAR = "whileCondition_"; private static string ConditionIdentifier { get { return CONDITION_VAR + CONDITION_COUNTER++; } } private readonly List markedNodes = new List(); private readonly List> replacementNodes = new List>(); //STEP 1 public override SyntaxNode VisitWhileStatement(WhileStatementSyntax node) { var nodeVisited = (WhileStatementSyntax) base.VisitWhileStatement(node); var condition = nodeVisited.Condition; if (condition.Kind() == SyntaxKind.IdentifierName) return nodeVisited; string conditionVarIdentifier = ConditionIdentifier; var newConditionVar = SyntaxFactoryExtensions.GenerateLocalVariableDeclaration(conditionVarIdentifier, condition, SyntaxKind.BoolKeyword).NormalizeWhitespace().WithTriviaFrom(nodeVisited); var newCondition = SyntaxFactory.IdentifierName(conditionVarIdentifier).WithTriviaFrom(condition); markedNodes.Add(condition); markedNodes.Add(node); replacementNodes.Add(new Tuple(condition, newCondition, newConditionVar, node)); return nodeVisited; } //STEP 2 private BlockSyntax ReplaceNodes(BlockSyntax oldBody) { oldBody = oldBody.TrackNodes(this.markedNodes); foreach (var tuple in this.replacementNodes) { var currentA = oldBody.GetCurrentNode(tuple.Item1); if (currentA != null) { var whileStatement = currentA.Parent; oldBody = oldBody.InsertNodesBefore(whileStatement, new List() { tuple.Item3 }); var currentB = oldBody.GetCurrentNode(tuple.Item1); oldBody = oldBody.ReplaceNode(currentB, tuple.Item2); var currentWhile = oldBody.GetCurrentNode(tuple.Item4); //modify body var whileBody = currentWhile.Statement as BlockSyntax; //create new statement var localCondition = tuple.Item3 as LocalDeclarationStatementSyntax; var initializer = localCondition.Declaration.Variables.First(); var assignment = SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName(initializer.Identifier), initializer.Initializer.Value)); var newStatements = whileBody.Statements.Add(assignment); whileBody = whileBody.WithStatements(newStatements); //updateWhile var newWhile = currentWhile.WithStatement(whileBody); oldBody = oldBody.ReplaceNode(currentWhile, newWhile); } } return oldBody; } public BlockSyntax Refactor(BlockSyntax oldBody) { markedNodes.Clear(); replacementNodes.Clear(); //STEP 1 oldBody = (BlockSyntax)this.Visit(oldBody); //STEP 2 oldBody = this.ReplaceNodes(oldBody); return oldBody; } }