Pytanie Odejście od głównych konstruktorów


Podgląd C # 6 dla Visual Studio 2013 obsłużył podstawową funkcję konstruktorów, którą zdecydowała drużyna, a nie wejdzie do finalnego wydania. Niestety mój zespół zaimplementował ponad 200 klas przy użyciu podstawowych konstruktorów.

Szukamy teraz najprostszej ścieżki do migracji naszego źródła. Ponieważ jest to kwestia jednorazowa, działałby magiczny łańcuch zastępczy regex lub hacky parser.

Zanim spędzę dużo czasu na pisaniu takiej bestii, czy jest ktoś, kto już to zrobił lub zna lepszy sposób?


11
2017-12-12 18:29


pochodzenie


Czy możesz pokazać nam przykład, aby uzyskać lepszy pomysł. - ja72
Nieco szalony pomysł: użyj wersji Roslyn w tym podglądzie, aby przepisać kod. Zasadniczo, dodaj odniesienie do bibliotek DLL Roslyn, które zostały zainstalowane wraz z podglądem, i poproś o zbudowanie swojego rozwiązania. Następnie dla każdej kompilacji przeszukaj drzewo składniowe dla węzłów podstawowego konstruktora i odpowiednio zmodyfikuj drzewo składni. Jeśli używasz parametrów w inicjalizatorach, to może być trochę owłosione. Poważnie rozważałbym robienie tego ręcznie - nużące, ale na dłuższą metę może być szybsze. - Jon Skeet
200 nie brzmi jak duża liczba. Ilu jest w twoim zespole? Jeśli zaczęli przekształcać kod, gdy pisałeś to pytanie, to by je ukończyli. - Sriram Sakthivel
Przepraszam, że oczywiste, ale wiesz, że nie powinieneś używać oprogramowania do wstępnego zapisu kodu do produkcji, prawda? - Gigi
@Gigi Takie ogólne, nakazowe oświadczenie nie ma w moim przekonaniu miejsca w StackOverflow. Co by było, gdybyśmy mieli wstępną wersję? Nie wspominając o tym, zaczęliśmy używać kompilatora z szeroko otwartymi oczami i świadomością potencjalnego ryzyka. Komentowanie potencjalnego ryzyka byłoby jedną rzeczą, ale nie jesteś w moich butach lub w moim zespole i nie możesz znać szczegółów tego, co spowodowało, że doszliśmy do decyzji o użyciu kompilatora przed wydaniem. - David Pfeffer


Odpowiedzi:


Jak zasugerowałem w komentarzach, mógłbyś użyć wersji Roslyn która robi poznaj podstawowe konstruktory, aby przeanalizować kod w drzewie składni, a następnie zmodyfikuj to drzewo składniowe, aby używał "normalnego" konstruktora. Musiałbyś umieścić wszystkie inicjalizatory, które używają podstawowych parametrów konstruktora również w nowym konstruktorze, uważam.

Podejrzewam, że zajmie to napisanie tego kodu mnie co najmniej dwie lub trzy godziny, a może nawet więcej - podczas gdy ja mógłbym wykonywać pracę ręcznie dla naprawdę całkiem wielu zajęć w tym samym czasie. Automatyka jest świetna, ale czasami najszybszym rozwiązaniem jest robienie rzeczy ręcznie ... nawet 200 klas może być szybszych do zrobienia ręcznie, a Ty możesz Zdecydowanie zrównoważyć pracę wielu osób.


6
2018-01-23 16:35





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

Kilka odpowiedzi: pierwsza z prostym znalezieniem i zamianą Regexa, którą musisz powtórzyć kilka razy:

  1. Regex: Kilka linii wyjaśnienia, a następnie aktualny ciąg regex i ciąg zastępczy:

    za. W regex najpierw dopasujesz pełny ciąg tego, czego szukasz (w twoim przypadku główny konstruktor). Nie trudno zrobić: wyszukaj nawias klamrowy, słowo publiczne, potem dwa słowa i znak równości itd. Każdy tekst znaleziony zgodnie z tym jest nazywany Dopasowaniem.

    b. Czasami możliwe są powtarzające się sekwencje w tekście, którego szukasz. (W twoim przypadku: parametry są zdefiniowane w wierszu dla każdego). W tym celu po prostu oznacz oczekiwaną sekwencję jako grupę, otaczając ją nawiasami.

    do. Następnie należy oznaczyć różne części znalezionego elementu, aby można było z nich korzystać lub zastąpić je poprawionym tekstem. Te części są również nazywane "grupami", a właściwie "grupami przechwytywania". Ponownie po prostu otocz części za pomocą nawiasów. W twoim przypadku zachowasz pierwszą przechwyconą grupę (nawias klamrowy) i nazwę właściwości z przypisaniem do parametru.

    re. Oto wyrażeń regularnych:

    (\{\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. 
    

Ciąg zastępujący to

\1\2\4\6

To pozostawia:

{ 
    [old corrected code] 
    [new corrected line]
    possible remaining lines to be corrected. 
  1. Notepad ++ 10 minut prób i błędów. Gwarantuję, że nie zabiorę cię więcej.

  2. Visual Studio 2014 refactor. ale za. Musisz zainstalować go na oddzielnej maszynie wirtualnej lub komputerze. MS ostrzega, aby nie instalować go równolegle z istniejącym kodem. b. Nie jestem pewien, czy refaktor działa w drugą stronę. [Here's an article about it][1]

  3. Makra programu Visual Studio. Wiem, że wiem, dawno już minęły, ale są co najmniej dwie wtyczki, które je zastępują, a może i więcej. Czytałem o nich na ta dyskusja SO (StackOverflow). (Dają kilka innych opcji) Tutaj:

  4. Visual Commander - Bezpłatny dodatek do makr programu Visual Studio z otwartym kodem źródłowym
  5. VSScript - dodatek Visual Studio: kosztuje 50 $ !!

  6. Próbować Automatyczne Regexp przez przykład: Podajesz kilka przykładów kodu, w którym podkreślisz IS, który jest oczekiwanym rezultatem, a następnie ten sam (lub inny) kod, w którym podkreślisz, CO NIE jest oczekiwanym rezultatem. Poczekaj, aż przejdzie przez przykłady i poda ci kod regex.

    // dla następującego kodu (od http://odetocode.com/blogs/scott/archive/2014/08/14/c-6-0-features-part-ii-primary-constructors.aspx )

    public struct Money (waluta łańcuchowa, liczba dziesiętna) {     public string Waluta {get; } = waluta;     publiczna kwota dziesiętna {get; } = kwota; } // Otrzymuję coś takiego: {++ \ w \ w [^ r-u] [^ _] ++ | [^ {] ++ (? = {\ W ++ =)

  7. Zagraj z regexp na tej wspaniałej stronie: https://www.regex101.com/

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

Powtarzana sekwencja linii konstruktora pierwotnego ("powtarzana grupa przechwytywania") przechwytuje tylko ostatnią.

  1. Użyj kodu c # z regex.captures jak wyjaśniono tutaj w innym StackOverflow (patrz zaakceptowana odpowiedź)

3
2018-01-24 23:31