#c# #roslyn
#c# #рослин
Вопрос:
Я пытаюсь переписать код с помощью Roslyn. Я хочу изменить Greater Thantoken на EqualsEqualsToken. Вот мой код на данный момент:
ToParse.cs:
public class ToParse
{
public bool MethodToConvert(int param)
{
return (1 > param);
}
}
Program.cs Программа.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);
После выполнения выполните консоль.WriteLine печатает измененные токены return (1 == param);
Но когда я открываю testassembly.dll с ilspy я все еще вижу return 1 > param;
Есть какие-нибудь предложения?
Комментарии:
1. вы перестроили проект?
2. ДА. Я также попробовал конфигурацию отладки / выпуска
3. Roslyn не позволяет вам переписывать во время компиляции.
4. Но он должен иметь возможность переписывать перед компиляцией, что, я полагаю, имеет место здесь.
Ответ №1:
[Примечание: вы используете немного более старую версию Roslyn. Этот ответ должен работать и для этой версии, но я могу ссылаться на классы и члены по более свежим именам, чтобы они соответствовали источнику, доступному в CodePlex.]
Исходное дерево, которое вы проанализировали, содержит BinaryExpressionSyntax
узел с символом SyntaxKind
of GreaterThanExpression
. Когда вы меняете GreaterThanToken
EqualsEqualsToken
местами внутри this BinaryExpressionSyntax
, он автоматически не настраивает SyntaxNode
вид содержимого на . EqualsExpression
В результате вы получите a GreaterThanExpression
с an EqualsEqualsToken
. Поскольку это не синтаксическое дерево, которое могло быть законно сгенерировано самим компилятором, вы можете увидеть неожиданное поведение, подобное этому.
Чтобы сгенерировать правильное дерево в этом случае, я бы рекомендовал переписать сам узел вместо токена, переопределив CSharpSyntaxRewriter.VisitBinaryExpression
и выполнив что-то вроде этого:
public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node)
{
if (node.CSharpKind() == SyntaxKind.GreaterThanExpression)
{
return SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, node.Left, node.Right);
}
return node;
}
Комментарии:
1. Разве какая-то часть процесса компиляции не должна проверять, что синтаксическое дерево не содержит ошибок такого рода?