Я столкнулся с непростой ситуацией при использовании SyntaxRewriter в Roslyn. Я хотел бы переписать некоторые виды операторов, в том числе объявления локальных переменных. Решение требует от меня преобразования рассматриваемых утверждений в несколько утверждений, как в следующем тривиальном примере:
void method()
{
int i;
}
становится
void method()
{
int i;
Console.WriteLine("I declared a variable.");
}
Я видел другие примеры, где блоки используются для достижения чего-то похожего, но, конечно, в случае объявления переменной, область объявления будет затронута. Я придумал следующее решение, но я отказываюсь от него. Это кажется слишком сложным и требует перерыва в шаблоне посетителей:
class Rewriter: SyntaxRewriter
{
public override SyntaxList<TNode> VisitList<TNode>(SyntaxList<TNode> list)
{
if (typeof(TNode) == typeof(StatementSyntax))
return Syntax.List<TNode>(list.SelectMany(st => RewriteStatementInList(st as StatementSyntax).Cast<TNode>()));
else
return base.VisitList<TNode>(list);
}
private IEnumerable<SyntaxNode> RewriteStatementInList(StatementSyntax node)
{
if (node is LocalDeclarationStatementSyntax)
return PerformRewrite((LocalDeclarationStatementSyntax)node);
//else if other cases (non-visitor)
return Visit(node).AsSingleEnumerableOf();
}
private IEnumerable<SyntaxNode> PerformRewrite(LocalDeclarationStatementSyntax orig)
{
yield return orig;
yield return Syntax.ParseStatement("Console.WriteLine(\"I declared a variable.\");");
}
}
Чего мне не хватает? Редактирование операторов и их удаление (через пустые операторы) кажутся более простыми, чем переписывание в кратные.
Мой взгляд на ответ:
class Rewriter : SyntaxRewriter
{
readonly ListVisitor _visitor = new ListVisitor();
public override SyntaxList<TNode> VisitList<TNode>(SyntaxList<TNode> list)
{
var result = Syntax.List(list.SelectMany(_visitor.Visit).Cast<TNode>());
return base.VisitList(result);
}
private class ListVisitor : SyntaxVisitor<IEnumerable<SyntaxNode>>
{
protected override IEnumerable<SyntaxNode> DefaultVisit(SyntaxNode node)
{
yield return node;
}
protected override IEnumerable<SyntaxNode> VisitLocalDeclarationStatement(
LocalDeclarationStatementSyntax node)
{
yield return node;
yield return Syntax.ParseStatement("Console.WriteLine(\"I declared a variable.\");");
}
}
}