Оказывается, что правильный класс для этого - CSharpSyntaxRewriter
, подкласс CSharpSyntaxVisitor
, который может значительно облегчить навигацию по деревьям синтаксиса.
Он функционально работает так же, как CSharpSyntaxVisitor
, но позволяет изменять синтаксические узлы.
Вот моя реализация класса:
public class AssignmentReplacer : CSharpSyntaxRewriter
{
private string inMethod;
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
{
inMethod = node.Identifier.ValueText;
return base.VisitMethodDeclaration(node);
}
public override SyntaxNode VisitAssignmentExpression(AssignmentExpressionSyntax node)
{
if (inMethod == "DoSomethingElse")
{
if (node.Left is IdentifierNameSyntax name &&
name.Identifier.Text == "_visited")
{
return node.Update(node.Left,
node.OperatorToken,
SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression));
}
}
return base.VisitAssignmentExpression(node);
}
}
По мере того, как он обходит дерево в глубинуон отслеживает свое текущее местоположение метода из VisitMethodDeclaration
в приватном поле.Он использует это в VisitAssignmentExpression
, чтобы убедиться, что он используется в правильном методе при изменении узла.
Как только он определил узел AssignmentExpressionSyntax
внутри правильного метода, он создает измененную копию узлас правой стороной, измененной на новую LiteralExpression
.
Возможно, вам придется добавить дополнительные проверки, чтобы убедиться, что вы модифицируете правильный узел, но это работает для ваших простых примеров данных.
Вы можете использовать класс следующим образом:
var programText =
@"public class Callee
{
private bool _visited = false;
public void DoSomethingElse()
{
_visited = false;
}
}";
var tree = CSharpSyntaxTree.ParseText(programText);
var root = tree.GetRoot();
var visitor = new AssignmentReplacer();
var updated = visitor.Visit(root);
После запуска посетителя updated
будет содержать измененный код:
public class Callee
{
private bool _visited = true;
public void DoSomethingElse()
{
_visited = true;
}
}
Простов качестве предостережения, я впервые делаю что-либо из этого, так что это может быть не самый эффективный или лучший способ сделать это.
Спасибо за интересный вызов!
Полностью работающий пример LINQPad можно найти здесь .