简体   繁体   中英

Roslyn SyntaxTree - Changing Field value

using the Roslyn SyntaxTree API, I'd like to replace the literal value "UV254" with a new value. Example:

public class Analog
{
   public const string Value = "UV254";
}

After update

public class Analog
{
   public const string Value = "UV220";
}

I came up with the below solution but I suspect this could be simplified:

string sourceCode = "public class Analog { public const string Value = \"UV254\"; public const string Description = \"A Description\";}";

SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(sourceCode);
CompilationUnitSyntax syntaxRoot = syntaxTree.GetCompilationUnitRoot();

LiteralExpressionSyntax afterLiteralExpressionSyntax = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal("UV220"));

LiteralExpressionSyntax beforeLiteralExpressionSyntax = null;
foreach (VariableDeclarationSyntax variableDeclarationSyntax in syntaxRoot.DescendantNodes().OfType<VariableDeclarationSyntax>())
{
    foreach(VariableDeclaratorSyntax variableDeclaratorSyntax in variableDeclarationSyntax.Variables)
    {
        if(variableDeclaratorSyntax.Identifier.ValueText == "Value")
        {
            beforeLiteralExpressionSyntax = variableDeclaratorSyntax.DescendantNodes().OfType<LiteralExpressionSyntax>().Single();
            break;
        }
    }
    if(beforeLiteralExpressionSyntax != null)
    {
        break;
    }
}
var newRoot = syntaxRoot.ReplaceNode(beforeLiteralExpressionSyntax, afterLiteralExpressionSyntax);
var fixedTree = newRoot.SyntaxTree.WithRootAndOptions(newRoot, syntaxTree.Options);

Can this be simplified? Thanks for the help.

I think you can use some LINQ to shorten the determination of beforeLiteralExpressionSyntax . You could write the following instead:

            LiteralExpressionSyntax beforeLiteralExpressionSyntax =
                syntaxRoot.DescendantNodes().OfType<VariableDeclarationSyntax>()
                .SelectMany(decl => decl.Variables)
                .FirstOrDefault(declarator => declarator.Identifier.ValueText == "Value")
                ?.DescendantNodes().OfType<LiteralExpressionSyntax>()
                .Single();

This will assign a null value to beforeLiteralExpressionSyntax if the field wasn't found. If you're sure the field will always be there, you could replace FirstOrDefault with First and replace the ?. with . .

Other than that, I don't think there is much you can do to simplify the code. My experience of working with Roslyn is that ultimately it is quite complicated to navigate through the syntax tree, pick out relevant bits of it and make changes to it, but I guess some of that is inevitable because it reflects the complexity of the C# language.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM