Tôi đã gặp phải một tình huống khó khăn khi sử dụng SyntaxRewriter trong Roslyn. Tôi muốn viết lại một số loại câu lệnh, bao gồm các khai báo biến cục bộ. Các giải pháp đòi hỏi tôi phải thay đổi những điều khoản trong câu hỏi thành nhiều báo cáo, như trong ví dụ tầm thường như sau:SyntaxRewriter và nhiều câu lệnh
void method()
{
int i;
}
trở thành
void method()
{
int i;
Console.WriteLine("I declared a variable.");
}
Tôi đã nhìn thấy những ví dụ khác, nơi khối được sử dụng để thực hiện một cái gì đó tương tự, nhưng tất nhiên trong trường hợp của một tuyên bố biến, phạm vi của tuyên bố sẽ bị ảnh hưởng. Tôi đã đưa ra giải pháp sau đây, nhưng tôi đang balking vào nó. Có vẻ như quá phức tạp và yêu cầu ngắt trong mẫu khách truy cập:
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.\");");
}
}
Tôi đang thiếu gì? Các câu lệnh chỉnh sửa và xóa chúng (thông qua câu lệnh trống) có vẻ thẳng về phía trước hơn là viết lại cho các bội số.
tôi đảm nhận câu trả lời:
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.\");");
}
}
}
Tôi đã nghĩ đến việc làm theo cách này. Phía chỉ xuống sẽ là IEnumerable sẽ chỉ có ý nghĩa bên trong một cuộc gọi đến VisitList. Tôi nghĩ rằng một người xây dựng/nhà văn, sẽ là một câu trả lời hấp dẫn, nhưng tôi nghĩ rằng tôi quá ám ảnh về nó :) Tôi sẽ upvote bạn guys sau, rõ ràng tôi không có đủ SO clout nào được nêu ra. –
Tại sao nó là một vấn đề mà 'IEnumerable' có ý nghĩa chỉ trong một cuộc gọi đến' VisitList() '? Bất cứ khi nào nó có ý nghĩa để thay thế một nút với một chuỗi các nút, nút đó phải là một phần của một số danh sách, tôi nghĩ. – svick
Trên thực tế, tôi đã không nhận thấy bạn chỉ gọi 'Visitor' trực tiếp và chỉ từ 'VisitList'. Tôi thích giải pháp này rất nhiều.Tôi sẽ đặt nó trong câu hỏi của tôi, với 'lợi nhuận' để tạo ra các vòng lặp và lồng vào lớp danh sách khách truy cập. –