我正在尝试了解 Roslyn 编译器的工作原理。
我正在尝试编写简单的函数,它将分析代码并将循环语句从递增更改为递减。
例如改变:
for(int i=0; i<10; i++)
int a = i;
到:
for(int i=9; i>=0; i--)
int a=i;
我已经编写了很早的代码来找到那个循环,但我不知道如何编辑它。
这是我到目前为止所做的:
SyntaxTree tree = CSharpSyntaxTree.ParseText(
@"using System;
using System.Collections.Generic;
using System.Text;
static void Main(string[] args)
{
for(int i=0; i<10; i++)
int a = i;
}");
var root = (CompilationUnitSyntax)tree.GetRoot();
IEnumerable<ForStatementSyntax> forStatementSyntaxs = root.DescendantNodes().OfType<ForStatementSyntax>();
ForStatementSyntax forStatementSyntax = forStatementSyntaxs.First();
ExpressionSyntax expressionSyntax = forStatementSyntax.Incrementors.First();
我想知道如何使用 Roslyn“for 循环”声明进行更改。此外,如何更改该循环包含的表达式。
最佳答案
创建一个 SyntaxRewriter,它是一个访问者,可用于用您创建的新节点替换语法树中的节点。还有适用于所有节点的方法,可用于创建对其进行更改的新节点。
在您的例子中,您想要创建一个新的 ForStatementSyntax
节点,并更改条件和语句。因此,您可以使用 WithCondition()
和 WithStatement()
方法分别进行更新。您可以手动创建新节点,也可以使用众多 SyntaxFactory
方法之一来解析字符串。
例如,
class Rewriter : CSharpSyntaxRewriter
{
public override SyntaxNode VisitForStatement(ForStatementSyntax node)
{
// update the current node with the new condition and statement
return node.WithCondition(
SyntaxFactory.ParseExpression("i>=0")
).WithStatement(
SyntaxFactory.ParseStatement(@"{
Console.WriteLine(i);
Console.WriteLine(i*2);
}")
);
}
}
创建访问者后,您可以简单地使用它。
var root = SyntaxFactory.ParseCompilationUnit(
@"using System;
using System.Collections.Generic;
using System.Text;
static void Main(string[] args)
{
for(int i=0; i<10; i++)
int a = i;
}");
var rewritten = new Rewriter().Visit(root);
另一方面,对于更简单的重写任务,您不一定需要重写器。您可以只使用 Replace 扩展方法来替换树中的节点。
var forStmt = root.DescendantNodes().OfType<ForStatementSyntax>().Single();
var rewritten = root.ReplaceNode(forStmt,
forStmt.WithCondition(
SyntaxFactory.ParseExpression("i>=0")
).WithStatement(
SyntaxFactory.ParseStatement(@" {
Console.WriteLine(i);
Console.WriteLine(i*2);
}
")
));
关于c# - 在 Roslyn 中编辑循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25568802/