Generowanie kodu czasu projektowania przy użyciu szablonów tekstowych T4

Szablony tekstowe T4 czasu projektowania umożliwiają generowanie kodu programu i innych plików w projekcie programu Visual Studio. Zazwyczaj szablony są zapisywane w taki sposób, aby różniły się one kodem generowanym zgodnie z danymi z modelu. Model to plik lub baza danych zawierająca kluczowe informacje o wymaganiach aplikacji.

Można na przykład mieć model definiujący przepływ pracy jako tabelę lub diagram. Na podstawie modelu można wygenerować oprogramowanie, które wykonuje przepływ pracy. Po zmianie wymagań użytkowników można łatwo omówić nowy przepływ pracy z użytkownikami. Ponowne generowanie kodu z przepływu pracy jest bardziej niezawodne niż ręczne aktualizowanie kodu.

Uwaga

Model to źródło danych, które opisuje konkretny aspekt aplikacji. Może to być dowolny formularz, w dowolnym rodzaju pliku lub bazie danych. Nie musi być w żadnej konkretnej formie, takiej jak model UML lub model języka specyficznego dla domeny. Typowe modele są w postaci tabel lub plików XML.

Prawdopodobnie znasz już generowanie kodu. Podczas definiowania zasobów w pliku resx w rozwiązaniu programu Visual Studio jest generowany automatycznie zestaw klas i metod. Plik zasobów znacznie ułatwia i bardziej niezawodną edycję zasobów niż gdyby trzeba było edytować klasy i metody. Szablony tekstu umożliwiają generowanie kodu w taki sam sposób ze źródła własnego projektu.

Szablon tekstowy zawiera kombinację tekstu, który chcesz wygenerować, oraz kod programu, który generuje zmienne części tekstu. Kod programu umożliwia powtarzanie lub warunkowe pomijanie części wygenerowanego tekstu. Wygenerowany tekst może być kodem programu, który będzie częścią aplikacji.

Tworzenie szablonu tekstowego T4 czasu projektowania

  1. Utwórz nowy projekt programu Visual Studio lub otwórz istniejący.

  2. Dodaj plik szablonu tekstowego do projektu i nadaj mu nazwę z rozszerzeniem tt.

    W tym celu w Eksplorator rozwiązań w menu skrótów projektu wybierz pozycję Dodaj>nowy element. W oknie dialogowym Dodawanie nowego elementu wybierz pozycję Szablon tekstowy w środkowym okienku.

    Zwróć uwagę, że właściwość Custom Tool pliku to TextTemplatingFileGenerator.

  3. Otwórz plik . Będzie już zawierać następujące dyrektywy:

    <#@ template hostspecific="false" language="C#" #>
    <#@ output extension=".txt" #>
    

    Jeśli szablon został dodany do projektu Języka Visual Basic, atrybut języka będzie mieć wartość "VB".

  4. Dodaj tekst na końcu pliku. Na przykład:

    Hello, world!
    
  5. Zapisz plik.

    Może zostać wyświetlone okno komunikatu Ostrzeżenie o zabezpieczeniach z prośbą o potwierdzenie, że chcesz uruchomić szablon. Kliknij przycisk OK.

  6. W Eksplorator rozwiązań rozwiń węzeł pliku szablonu i znajdziesz plik z rozszerzeniem .txt. Plik zawiera tekst wygenerowany na podstawie szablonu.

    Uwaga

    Jeśli projekt jest projektem Visual Basic, musisz kliknąć pozycję Pokaż wszystkie pliki , aby wyświetlić plik wyjściowy.

Ponowne generowanie kodu

Szablon zostanie wykonany, generując plik zależny, w dowolnym z następujących przypadków:

  • Edytuj szablon, a następnie zmień fokus na inne okno programu Visual Studio.

  • Zapisz szablon.

  • Kliknij pozycję Przekształć wszystkie szablony w menu Kompilacja. Spowoduje to przekształcenie wszystkich szablonów w rozwiązaniu programu Visual Studio.

  • W Eksplorator rozwiązań w menu skrótów dowolnego pliku wybierz pozycję Uruchom narzędzie niestandardowe. Ta metoda służy do przekształcania wybranego podzestawu szablonów.

Można również skonfigurować projekt programu Visual Studio, aby szablony były wykonywane po zmianie plików danych, które odczytują. Aby uzyskać więcej informacji, zobacz Ponowne generowanie kodu automatycznie.

Generowanie tekstu zmiennej

Szablony tekstu umożliwiają używanie kodu programu w celu zmiany zawartości wygenerowanego pliku.

  1. Zmień zawartość .tt pliku:

    <#@ template hostspecific="false" language="C#" #>
    <#@ output extension=".txt" #>
    <#int top = 10;
    
    for (int i = 0; i<=top; i++)
    { #>
       The square of <#= i #> is <#= i*i #>
    <# } #>
    
  2. .tt Zapisz plik i sprawdź wygenerowany plik .txt ponownie. Zawiera listę kwadratów liczb z zakresu od 0 do 10.

    Zwróć uwagę, że instrukcje są ujęte w wyrażenia <#...#>, i w obrębie <#=...#>. Aby uzyskać więcej informacji, zobacz Pisanie szablonu tekstowego T4.

    Jeśli napiszesz kod generowania w Visual Basic, template dyrektywa powinna zawierać wartość language="VB". Wartość domyślna to "C#".

Debugowanie szablonu tekstowego T4 czasu projektowania

Aby debugować szablon tekstowy:

  • Wstaw debug="true" do template dyrektywy. Na przykład:

    <#@ template debug="true" hostspecific="false" language="C#" #>

  • Ustaw punkty przerwania w szablonie w taki sam sposób, jak w przypadku zwykłego kodu.

  • Wybierz pozycję Debuguj szablon T4 z menu skrótów pliku szablonu tekstowego w Eksplorator rozwiązań.

    Szablon jest uruchamiany i zatrzymuje się w punktach przerwania. Możesz sprawdzić zmienne i przejść przez kod w zwykły sposób.

Napiwek

debug="true" sprawia, że wygenerowana mapa kodu jest bardziej dokładna dla szablonu tekstowego, wstawiając więcej dyrektyw numerowania wierszy do wygenerowanego kodu. Jeśli go opuścisz, punkty przerwania mogą zatrzymać przebieg w niewłaściwym stanie.

Możesz jednak pozostawić klauzulę w dyrektywie szablonu nawet wtedy, gdy nie debugujesz. Powoduje to tylko bardzo mały spadek wydajności.

Generowanie kodu lub zasobów dla rozwiązania

W zależności od modelu można wygenerować pliki programu, które się różnią. Model to dane wejściowe, takie jak baza danych, plik konfiguracji, model UML, model DSL lub inne źródło. Zwykle generujesz kilka plików programu z tego samego modelu. W tym celu utworzysz plik szablonu dla każdego wygenerowanego pliku programu i wszystkie szablony będą odczytywać ten sam model.

Generowanie kodu lub zasobów programu

  1. Zmień dyrektywę wyjściową, aby wygenerować plik odpowiedniego typu, taki jak .cs, .vb, resx lub .xml.

  2. Wstaw kod, który wygeneruje wymagany kod rozwiązania. Jeśli na przykład chcesz wygenerować trzy deklaracje pól całkowitych w klasie:

    
    <#@ template debug="false" hostspecific="false" language="C#" #>
    <#@ output extension=".cs" #>
    <# var properties = new string [] {"P1", "P2", "P3"}; #>
    // This is generated code:
    class MyGeneratedClass {
    <# // This code runs in the text template:
      foreach (string propertyName in properties)  { #>
      // Generated code:
      private int <#= propertyName #> = 0;
    <# } #>
    }
    
  3. Zapisz plik i sprawdź wygenerowany plik, który zawiera teraz następujący kod:

    class MyGeneratedClass {
      private int P1 = 0;
      private int P2 = 0;
      private int P3 = 0;
    }
    

Generowanie kodu i wygenerowanego tekstu

Podczas generowania kodu programu najważniejsze jest unikanie mylącego generowania kodu wykonywanego w szablonie oraz wynikowego wygenerowanego kodu, który staje się częścią rozwiązania. Dwa języki nie muszą być takie same.

W poprzednim przykładzie istnieją dwie wersje. W jednej wersji kod generowania znajduje się w języku C#. W drugiej wersji kod generowania to Visual Basic. Jednak tekst wygenerowany przez obie te elementy jest taki sam i jest klasą języka C#.

W ten sam sposób można użyć szablonu języka Visual C#, aby wygenerować kod w dowolnym języku. Wygenerowany tekst nie musi być w żadnym konkretnym języku i nie musi być kodem programowym.

Tworzenie struktury szablonów tekstu

W ramach dobrej praktyki zwykle dzielimy kod szablonu na dwie części:

  • Część konfiguracji lub zbierania danych, która ustawia wartości w zmiennych, ale nie zawiera bloków tekstowych. W poprzednim przykładzie ta część jest inicjowaniem elementu properties.

    Jest to czasami nazywana sekcją "model", ponieważ tworzy model w sklepie i zazwyczaj odczytuje plik modelu.

  • Część generowania tekstu (foreach(...){...} w przykładzie), która używa wartości zmiennych.

    Nie jest to konieczne rozdzielenie, ale jest to styl, który ułatwia odczytywanie szablonu przez zmniejszenie złożoności części zawierającej tekst.

Odczytywanie plików lub innych źródeł

Aby uzyskać dostęp do pliku modelu lub bazy danych, kod szablonu może używać zestawów, takich jak System.XML. Aby uzyskać dostęp do tych zestawów, należy wstawić dyrektywy, takie jak:

<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.IO" #>

Dyrektywa assembly udostępnia określony zestaw kodowi szablonu w taki sam sposób, jak sekcja Odwołania projektu programu Visual Studio. Nie musisz dołączać odwołania do System.dll, do którego odwołuje się automatycznie. Dyrektywa import umożliwia używanie typów bez używania ich w pełni kwalifikowanych nazw w taki sam sposób jak using dyrektywa w zwykłym pliku programu.

Na przykład po zaimportowaniu System.IO można napisać:


<# var properties = File.ReadLines("C:\\propertyList.txt");#>
...
<# foreach (string propertyName in properties) { #>
...

Otwieranie pliku z względną nazwą ścieżki

Aby załadować plik z lokalizacji względem szablonu tekstowego, możesz użyć polecenia this.Host.ResolvePath(). Aby użyć this.Hostelementu , należy ustawić hostspecific="true" w elemecie template:

<#@ template debug="false" hostspecific="true" language="C#" #>

Następnie możesz napisać, na przykład:

<# string filename = this.Host.ResolvePath("filename.txt");
  string [] properties = File.ReadLines(filename);
#>
...
<#  foreach (string propertyName in properties { #>
...

Można również użyć elementu this.Host.TemplateFile, który identyfikuje nazwę bieżącego pliku szablonu.

Typ ( this.Host w VB, Me.Host) to Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost.

Pobieranie danych z programu Visual Studio

Aby korzystać z usług udostępnianych w programie Visual Studio, ustaw hostspecific atrybut i załaduj EnvDTE zestaw. Zaimportuj Microsoft.VisualStudio.TextTemplatingelement , który zawiera metodę GetCOMService() rozszerzenia. Następnie możesz użyć interfejsu IServiceProvider.GetCOMService(), aby uzyskać dostęp do usługi DTE i innych usług. Na przykład:

<#@ template hostspecific="true" language="C#" #>
<#@ output extension=".txt" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#
  IServiceProvider serviceProvider = (IServiceProvider)this.Host;
  EnvDTE.DTE dte = (EnvDTE.DTE) serviceProvider.GetCOMService(typeof(EnvDTE.DTE));
#>

Number of projects in this VS solution:  <#= dte.Solution.Projects.Count #>

Napiwek

Szablon tekstowy jest uruchamiany w własnej domenie aplikacji, a usługi są dostępne przez marshaling. W takiej sytuacji getCOMService() jest bardziej niezawodny niż GetService().

Ponowne generowanie kodu automatycznie

Zazwyczaj kilka plików w rozwiązaniu programu Visual Studio jest generowanych przy użyciu jednego modelu wejściowego. Każdy plik jest generowany na podstawie własnego szablonu, ale wszystkie szablony odwołują się do tego samego modelu.

Jeśli model źródłowy ulegnie zmianie, należy ponownie uruchomić wszystkie szablony w rozwiązaniu. Aby to zrobić ręcznie, wybierz pozycję Przekształć wszystkie szablony w menu Kompilacja .

Jeśli zainstalowano zestaw SDK modelowania programu Visual Studio, wszystkie szablony można przekształcić automatycznie za każdym razem, gdy wykonujesz kompilację. W tym celu zmodyfikuj plik projektu (csproj lub vbproj) w edytorze tekstów i dodaj następujące wiersze na końcu pliku po innych <import> instrukcjach. W projekcie w stylu zestawu SDK można przejść w dowolnym miejscu w pliku projektu.

Uwaga

Zestaw SDK przekształcania szablonu tekstu i zestaw SDK modelowania programu Visual Studio są instalowane automatycznie podczas instalowania określonych funkcji programu Visual Studio.

<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v17.0\TextTemplating\Microsoft.TextTemplating.targets" />
<PropertyGroup>
   <TransformOnBuild>true</TransformOnBuild>
   <!-- Other properties can be inserted here -->
</PropertyGroup>

Aby uzyskać więcej informacji, zobacz Generowanie kodu w procesie kompilacji.

Raportowanie błędów

Aby umieścić komunikaty o błędach i ostrzeżeniach w oknie błędu programu Visual Studio, można użyć następujących metod:

Error("An error message");
Warning("A warning message");

Konwertowanie istniejącego pliku na szablon

Przydatną funkcją szablonów jest to, że wyglądają bardzo podobnie do generowanych plików wraz z wstawionym kodem programu. Sugeruje to przydatną metodę tworzenia szablonu. Najpierw utwórz zwykły plik jako prototyp, taki jak plik Visual C#, a następnie stopniowo wprowadzaj kod generowania, który zmienia wynikowy plik.

Aby przekonwertować istniejący plik na szablon czasu projektowania

  1. W projekcie programu Visual Studio dodaj plik typu, który chcesz wygenerować, na przykład .csplik , .vblub .resx .

  2. Przetestuj nowy plik, aby upewnić się, że działa.

  3. W Eksplorator rozwiązań zmień rozszerzenie nazwy pliku na .tt.

  4. Sprawdź następujące właściwości pliku tt :

    Właściwości Ustawienie
    Narzędzie niestandardowe = Texttemplatingfilegenerator
    Akcja kompilacji = Brak
  5. Wstaw następujące wiersze na początku pliku:

    <#@ template debug="false" hostspecific="false" language="C#" #>
    <#@ output extension=".cs" #>
    

    Jeśli chcesz napisać kod generowania szablonu w Visual Basic, ustaw language atrybut na "VB" wartość zamiast "C#".

    extension Ustaw atrybut na rozszerzenie nazwy pliku dla typu pliku, który chcesz wygenerować, na przykład .cs, .resxlub .xml.

  6. Zapisz plik.

    Zostanie utworzony plik zależny z określonym rozszerzeniem. Jego właściwości są poprawne dla typu pliku. Na przykład właściwość Akcja kompilacji pliku .cs będzie kompilowana.

    Sprawdź, czy wygenerowany plik zawiera tę samą zawartość co oryginalny plik.

  7. Zidentyfikuj część pliku, który chcesz różnić. Na przykład część, która pojawia się tylko w określonych warunkach, lub część, która jest powtarzana lub gdzie określone wartości się różnią. Wstaw generowanie kodu. Zapisz plik i sprawdź, czy plik zależny jest poprawnie wygenerowany. Powtórz ten krok.

Wskazówki dotyczące generowania kodu

Zobacz Wskazówki dotyczące pisania szablonów tekstu T4.