简体   繁体   English

Roslyn SyntaxTree - 更改字段值

[英]Roslyn SyntaxTree - Changing Field value

using the Roslyn SyntaxTree API, I'd like to replace the literal value "UV254" with a new value.使用 Roslyn SyntaxTree API,我想用新值替换文字值“UV254”。 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 .我认为您可以使用一些 LINQ 来缩短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.如果未找到该字段,这会将null值分配给beforeLiteralExpressionSyntax If you're sure the field will always be there, you could replace FirstOrDefault with First and replace the ?.如果您确定该字段将始终存在,则可以将FirstOrDefault替换为First并替换?. 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.我与 Roslyn 合作的经验是,最终浏览语法树、从中挑选出相关位并对其进行更改是相当复杂的,但我想其中一些是不可避免的,因为它反映了 C# 语言的复杂性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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