#c# #abstract-syntax-tree #roslyn
#c# #аннотация-синтаксическое дерево #roslyn
Вопрос:
используя Roslyn SyntaxTree 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);
Можно ли это упростить?
Спасибо за помощь.
Ответ №1:
Я думаю, вы можете использовать некоторый 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 #.
Комментарии:
1. Спасибо, мне нравится!