Roslyn SyntaxTree - 更改字段值
Roslyn SyntaxTree - Changing Field value
使用 Roslyn 语法树 API,我想用新值替换文字值“UV254”。
示例:
public class Analog
{
public const string Value = "UV254";
}
更新后
public class Analog
{
public const string Value = "UV220";
}
我提出了以下解决方案,但我怀疑这可以简化:
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);
这可以简化吗?
感谢您的帮助。
我认为您可以使用一些 LINQ 来缩短 beforeLiteralExpressionSyntax
的确定时间。您可以改写以下内容:
LiteralExpressionSyntax beforeLiteralExpressionSyntax =
syntaxRoot.DescendantNodes().OfType<VariableDeclarationSyntax>()
.SelectMany(decl => decl.Variables)
.FirstOrDefault(declarator => declarator.Identifier.ValueText == "Value")
?.DescendantNodes().OfType<LiteralExpressionSyntax>()
.Single();
如果未找到该字段,这会将 null
值分配给 beforeLiteralExpressionSyntax
。如果您确定该字段将始终存在,则可以将 FirstOrDefault
替换为 First
并将 ?.
替换为 .
.
除此之外,我认为您可以做很多事情来简化代码。我使用 Roslyn 的经验是,最终在语法树中导航、挑选出相关部分并对其进行更改是相当复杂的,但我想其中一些是不可避免的,因为它反映了 C# 语言的复杂性。
使用 Roslyn 语法树 API,我想用新值替换文字值“UV254”。 示例:
public class Analog
{
public const string Value = "UV254";
}
更新后
public class Analog
{
public const string Value = "UV220";
}
我提出了以下解决方案,但我怀疑这可以简化:
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);
这可以简化吗? 感谢您的帮助。
我认为您可以使用一些 LINQ 来缩短 beforeLiteralExpressionSyntax
的确定时间。您可以改写以下内容:
LiteralExpressionSyntax beforeLiteralExpressionSyntax =
syntaxRoot.DescendantNodes().OfType<VariableDeclarationSyntax>()
.SelectMany(decl => decl.Variables)
.FirstOrDefault(declarator => declarator.Identifier.ValueText == "Value")
?.DescendantNodes().OfType<LiteralExpressionSyntax>()
.Single();
如果未找到该字段,这会将 null
值分配给 beforeLiteralExpressionSyntax
。如果您确定该字段将始终存在,则可以将 FirstOrDefault
替换为 First
并将 ?.
替换为 .
.
除此之外,我认为您可以做很多事情来简化代码。我使用 Roslyn 的经验是,最终在语法树中导航、挑选出相关部分并对其进行更改是相当复杂的,但我想其中一些是不可避免的,因为它反映了 C# 语言的复杂性。