使用Roslyn更改语法标记

问题描述 投票:3回答:1

我正在尝试用Roslyn重写代码。我想将GreaterThanToken更改为EqualsEqualsToken。到目前为止,这是我的代码:

ToParse.cs:

public class ToParse
{
    public bool MethodToConvert(int param)
    {
        return (1 > param);
    }
}

Program.cs中:

class Rewriter : SyntaxRewriter
{
    private readonly SyntaxKind _replace;
    private readonly SyntaxKind _replacewith;
    public Rewriter(SyntaxKind replace, SyntaxKind replacewith)
    {
        _replace = replace;
        _replacewith = replacewith;
    }

    public override SyntaxToken VisitToken(SyntaxToken token)
    {
        if (token.Kind != _replace)
            return token;

        return Syntax.Token(_replacewith);
    }
}

用法:

var code = new StreamReader("ToParse.cs").ReadToEnd();
var tree = SyntaxTree.ParseText(code);
var root = tree.GetRoot();
var rewriter = new Rewriter(SyntaxKind.GreaterThanToken, SyntaxKind.EqualsEqualsToken);
var newRoot = rewriter.Visit(root);

var newTree = SyntaxTree.Create((CompilationUnitSyntax)newRoot);
var compilation = Compilation.Create("TestAssembly.dll", 
      new CompilationOptions(OutputKind.DynamicallyLinkedLibrary),
      references: new[]{ new MetadataFileReference(typeof(object).Assembly.Location)},
      syntaxTrees: new[] { newTree });
Console.WriteLine(newTree);
EmitResult res;

using (var file = new FileStream("e:\\TestAssembly.dll", FileMode.Create))
   res = compilation.Emit(file);

执行后,Console.WriteLine打印更改的标记return (1 == param);但是当我用ilspy打开testassembly.dll时我仍然看到return 1 > param;有什么建议吗?

c# roslyn
1个回答
6
投票

[注意:你使用的是较旧版本的Roslyn。这个答案也适用于该版本,但我可以通过更新的名称引用类和成员,以便它们与CodePlex上的可用源匹配。

您解析的原始树包含一个BinaryExpressionSyntax节点,其SyntaxKindGreaterThanExpression。当你用GreaterThanToken中的EqualsEqualsToken替换BinaryExpressionSyntax时,它不会自动调整包含SyntaxNode的那种EqualsExpression

结果,你最终得到了GreaterThanExpressionEqualsEqualsToken。由于这不是编译器本身可以合法生成的语法树,因此您可能会看到类似的意外行为。

要在这种情况下生成正确的树,我建议通过重写CSharpSyntaxRewriter.VisitBinaryExpression来重写节点本身而不是令牌,并执行以下操作:

public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node)
{
    if (node.CSharpKind() == SyntaxKind.GreaterThanExpression)
    {
        return SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, node.Left, node.Right);
    }

    return node;
}
© www.soinside.com 2019 - 2024. All rights reserved.