Отойдя от первичных конструкторов

Предварительный просмотр C# 6 для Visual Studio 2013 поддерживал основную функцию конструкторов, которая, как решили специалисты, не войдет в финальную версию. К сожалению, моя команда реализовала более 200 классов с использованием первичных конструкторов.

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

Прежде чем я потрачу много времени на написание такого зверя, есть ли кто-нибудь, кто уже сделал это или знает лучший способ?

2 ответа

Решение

Как я предлагал в комментариях, вы можете использовать версию Roslyn, которая знает о первичных конструкторах, для синтаксического анализа кода в синтаксическом дереве, а затем изменить это синтаксическое дерево, чтобы вместо него использовать "нормальный" конструктор. Заметьте, что вам также нужно поместить все инициализаторы, которые используют параметры первичного конструктора, в новый конструктор.

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

(\{\s*)(\w*\s*?=\s*?\w*\s*?;\s*?)*?(public\s*\w*\s*)(\w*)(\s*?{\s*?get;\s*?\})(\s*?=\s*?\w*;\s*)
\1\2\4\5

Несколько ответов: первый с простым поиском и заменой Regex, который нужно повторить несколько раз:

  1. Регулярное выражение: несколько строк объяснения, а затем фактическая строка регулярного выражения и строка замены:

    а. В регулярном выражении вы сначала сопоставляете полную строку того, что ищете (в вашем случае основной конструктор). Нетрудно сделать: поиск фигурных скобок, слово public, затем два слова, знак равенства и т. Д. Каждый найденный в соответствии с этим текст называется Match.

    б. Иногда в тексте возможны повторяющиеся последовательности, которые вы ищете. (В вашем случае: параметры определены в строке для каждого). Для этого вы просто помечаете ожидаемую последовательность как Группу, заключая ее в круглые скобки.

    с. Затем вы хотите пометить разные части найденного, чтобы вы могли использовать их или заменить в исправленном тексте. Эти части также называются "Группы", на самом деле "Группы захвата". Снова просто окружите части круглыми скобками. В вашем случае вы сохраните первую захваченную группу (фигурную скобку) и имя свойства с его назначением параметру.

    д. Вот регулярное выражение:

    (\{\s*)(\w*\s*?=\s*?\w*\s*?;\s*?)*?(public\s*\w*\s*)(\w*)(\s*?{\s*?get;\s*?})(\s*?=\s*?\w*;\s*)
    
    1. ( 
          // ---- Capture1 -----
          {         
              // code: \{\s*? 
              // explained: curley bracket followed by possible whitespace
       ) 
    
    2. ( - Capture2  - previously corrected text 
          // - possible multiple lines of 'corrected' non-primary-constructors 
          // created during the find-replace process previously, 
    
          Propname = paramname;  // word,  equals-sign, word, semicolon 
          // code:  \w*\s*?=\s*?\w*\s*?;\s*?
          // explained:   \w - any alphanumeric, \s - any whitespace
          //              * - one or more times, *? - 0 or more times 
       )*?  
          // code: )*?
          // explained:  this group can be repeated zero or more times 
          // in other words it may not be found at all. 
          // These text lines are created during the recursive replacement process...
    
    3. ( 
          //  ----Capture 3-----
          // The first line of a primary constructor: 
          public type
          // code: public\s*\w*\s*  
          // explained: the word 'public' and then another word (and [whitespace]) 
        )
    
    4. (
        // ----- capture 4 -----
        Propname
         // code: \w@  
         // explained:  any amount of alphanumeric letters
       )
    
    5. (
         // ---- capture 5 ----
         { get; }
         // code: \s*?{\s*?get;\s*?\}
       )
    
    6. (
        // ---- capture 6 ----
         = propname; 
        code: \s*?=\s*?\w*;\s*
        explained: by now you should get it. 
    

Строка замены

\1\2\4\6

Это оставляет:

{ 
    [old corrected code] 
    [new corrected line]
    possible remaining lines to be corrected. 
  1. Блокнот ++ 10 минут проб и ошибок. Я гарантирую, это не займет у вас больше, чем это.

  2. Visual Studio 2014 рефакторинг. но а. Вы должны установить его на отдельную виртуальную машину или компьютер. MS предупреждает вас не устанавливать его рядом с существующим кодом. б. Я не уверен, что рефакторинг работает по-другому. [Here's an article about it][1]

  3. Макросы Visual Studio. Я знаю, я знаю, они давно ушли, но есть по крайней мере два плагина, которые заменяют их и, возможно, больше. Я читал о них в этом обсуждении (Stackru). (Они дают несколько других вариантов) Здесь:

  4. Visual Commander - бесплатное дополнение для макросов Visual Studio с открытым исходным кодом
  5. VSScript - дополнение Visual Studio: стоит $50!

  6. Попробуйте автоматическое регулярное выражение в качестве примера: вы даете ему несколько примеров кода, в котором вы выделяете то, что является ожидаемым результатом, а затем тот же (или другой) код, в котором вы выделяете то, что НЕ является ожидаемым результатом. Затем вы ждете, пока он пройдет через примеры, и дадите вам некоторый код регулярного выражения.

    // для следующего кода (с http://odetocode.com/blogs/scott/archive/2014/08/14/c-6-0-features-part-ii-primary-constructors.aspx)

    public struct Money (строковая валюта, десятичная сумма) { public string Currency { get; } = валюта; общедоступная десятичная сумма {get; } = сумма; } // Я получаю что-то вроде: { ++\w\w[^ru][^_]++|[^{]++(?={ \ W ++ =)

  7. Играйте с регулярным выражением на этом замечательном сайте: https://www.regex101.com/

    // I first tried: \{\s*((public\s*\w*\s*)\w*(\s*?{\s*?get;\s*?})\s*?=\s*?\w*;\s*)*\}
    

Повторяющаяся последовательность строк первичного конструктора ("группа повторного захвата") захватывает только последнюю.

  1. Используйте код C# с regex.captures как объяснено здесь в другом Stackru (см. принятый ответ)
Другие вопросы по тегам