Переписывание синтаксиса

Мне нужно преобразовать все свойства определенного класса с помощью Roslyn.

Каков рекомендуемый способ применения нескольких преобразований к синтаксическому дереву без аннулирования ссылок на него?


Вот что я пробовал и где я застрял:

  • На первом проходе потомок CSharpSyntaxWalker посещает все узлы PropertyDeclarationSyntax и сохраняет их в списке.

  • Во втором проходе CSharpSyntaxRewriter преобразует узлы, проверяя, что каждый посещенный узел равен единице в списке перед его преобразованием.

Проблема с моей попыткой заключается в следующем: когда я преобразую свойство, я добавляю новые поля в класс, что приводит к изменению класса. Все ссылки в списке на другие свойства становятся недействительными в новом дереве для класса.

Повторное посещение всего класса кажется неэффективным, и в любом случае я не могу обнаружить уже обработанные узлы свойств из-за разницы в ссылках.


person Liviu    schedule 29.05.2014    source источник
comment
Можешь подробнее описать, чем ты занимаешься? Может быть, показать какой-нибудь код?   -  person Dan Puzey    schedule 29.05.2014
comment
Я добавил больше информации в исходный пост   -  person Liviu    schedule 29.05.2014
comment
Я думаю, вам нужно просто опубликовать соответствующий код; мне не совсем понятно, что вы делаете.   -  person Dan Puzey    schedule 29.05.2014
comment
@DanPuzey Я отредактировал вопрос, пожалуйста, дайте мне знать, если то, что спрашивает ОП, теперь, по вашему мнению, яснее.   -  person Benjamin Gruenbaum    schedule 01.06.2014


Ответы (1)


Я бы не рекомендовал ссылаться на узлы из SyntaxTree, которые вы хотите изменить. В вашем случае будет достаточно просто использовать CSharpSyntaxRewriter за один проход (без сохранения ссылок из прохода предварительной обработки), потому что его метод VisitPropertyDeclaration будет вызываться только один раз для каждого свойства, поэтому нет необходимости чтобы отслеживать узлы, которые вы уже изменили.

CSharpSyntaxRewriter также посещает узлы снизу вверх, поэтому переопределения всегда следует вызывать с узлом из исходного дерева. Скорее всего, вы изменили node с помощью вызова base.VisitPropertyDeclaration(), прежде чем сравнивать его ссылку с сохраненной. Таким образом, вы все еще можете сохранять и сравнивать ссылки, если хотите.

public class PropertyRewriter : CSharpSyntaxRewriter
{
    public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node)
    {
        // 'node' should be still from the original syntax tree here

        node = (PropertyDeclarationSyntax)base.VisitPropertyDeclaration(node);

        // 'node' might be replaced here

        return node;
    }
}

Вместо того, чтобы сохранять ссылки на узлы, которые вы хотите изменить, вы можете аннотировать их. Аннотации к узлу сохранятся после модификации содержащего SyntraxTree до тех пор, пока сам узел не будет заменен. Вы можете добавить их следующим образом:

node = node.WithAdditionalAnnotations(
        new SyntaxAnnotation("propertyToChange", "todo"));

Чтобы снова получить аннотацию, либо используйте node.GetAnnotations("propertyToChange"), либо используйте GetAnnotatedNodesOrTokens("propertyToChange") для получения всех узлов или токенов с аннотацией данного типа ("propertyToChange").

person andyp    schedule 03.06.2014