Generowanie tekstu czasu wykonywania przy użyciu szablonów tekstowych T4

Ciągi tekstowe w aplikacji można wygenerować w czasie wykonywania przy użyciu szablonów tekstu środowiska uruchomieniowego programu Visual Studio. Komputer, na którym jest wykonywana aplikacja, nie musi mieć programu Visual Studio. Szablony środowiska uruchomieniowego są czasami nazywane "wstępnie przetworzonymi szablonami tekstu", ponieważ w czasie kompilacji szablon generuje kod wykonywany w czasie wykonywania.

Każdy szablon jest kombinacją tekstu, który będzie wyświetlany w wygenerowanym ciągu i fragmentach kodu programu. Fragmenty programu dostarczają wartości dla zmiennych części ciągu, a także kontrolują części warunkowe i powtarzające się.

Można na przykład użyć następującego szablonu w aplikacji, która tworzy raport HTML.

<#@ template language="C#" #>
<html><body>
<h1>Sales for Previous Month</h2>
<table>
    <# for (int i = 1; i <= 10; i++)
       { #>
         <tr><td>Test name <#= i #> </td>
             <td>Test value <#= i * i #> </td> </tr>
    <# } #>
 </table>
This report is Company Confidential.
</body></html>

Zwróć uwagę, że szablon jest stroną HTML, w której części zmiennych zostały zastąpione kodem programu. Możesz rozpocząć projektowanie takiej strony, pisząc statyczny prototyp strony HTML. Następnie można zastąpić tabelę i inne części zmiennych kodem programu, który generuje zawartość, która różni się od jednej okazji do następnej.

Użycie szablonu w aplikacji ułatwia wyświetlanie ostatecznej formy danych wyjściowych niż w przykładzie długiej serii instrukcji zapisu. Wprowadzanie zmian w postaci danych wyjściowych jest łatwiejsze i bardziej niezawodne.

Tworzenie szablonu tekstu w czasie wykonywania w dowolnej aplikacji

Aby utworzyć szablon tekstowy w czasie wykonywania

  1. W Eksplorator rozwiązań w menu skrótów projektu wybierz pozycję Dodaj>nowy element.

  2. W oknie dialogowym Dodawanie nowego elementu wybierz pozycję Szablon tekstowy środowiska uruchomieniowego. (W języku Visual Basic przyjrzyj się w obszarze Ogólne elementy> wspólne).

  3. Wpisz nazwę pliku szablonu.

    Uwaga

    Nazwa pliku szablonu będzie używana jako nazwa klasy w wygenerowanym kodzie. W związku z tym nie powinna zawierać spacji ani znaków interpunkcyjnych.

  4. Wybierz opcję Dodaj.

    Zostanie utworzony nowy plik z rozszerzeniem tt. Jego właściwość Custom Tool jest ustawiona na TextTemplatingFilePreprocessor. Zawiera on następujące wiersze:

    <#@ template language="C#" #>
    <#@ assembly name="System.Core" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Text" #>
    <#@ import namespace="System.Collections.Generic" #>
    
  5. Dodaj odwołanie do pakietu NuGet System.CodeDom.

Konwertowanie istniejącego pliku na szablon czasu wykonywania

Dobrym sposobem utworzenia szablonu jest przekonwertowanie istniejącego przykładu danych wyjściowych. Jeśli na przykład aplikacja wygeneruje pliki HTML, możesz zacząć od utworzenia zwykłego pliku HTML. Upewnij się, że działa poprawnie i że jego wygląd jest poprawny. Następnie dołącz go do projektu programu Visual Studio i przekonwertuj go na szablon.

Aby przekonwertować istniejący plik tekstowy na szablon czasu wykonywania

  1. Dołącz plik do projektu programu Visual Studio. W Eksplorator rozwiązań w menu skrótów projektu wybierz pozycję Dodaj>istniejący element.

  2. Ustaw właściwość Custom Tools pliku na TextTemplatingFilePreprocessor. W Eksplorator rozwiązań w menu skrótów pliku wybierz pozycję Właściwości.

    Uwaga

    Jeśli właściwość jest już ustawiona, upewnij się, że jest to TextTemplatingFilePreprocessor , a nie TextTemplatingFileGenerator. Może się tak zdarzyć, jeśli dołączysz plik, który ma już rozszerzenie .tt.

  3. Zmień rozszerzenie nazwy pliku na .tt. Mimo że ten krok jest opcjonalny, pomaga uniknąć otwierania pliku w nieprawidłowym edytorze.

  4. Usuń wszystkie spacje lub znaki interpunkcyjne z głównej części nazwy pliku. Na przykład "Moja Page.tt sieci Web" byłaby niepoprawna, ale "MyWebPage.tt" jest poprawna. Nazwa pliku będzie używana jako nazwa klasy w wygenerowanym kodzie.

  5. Wstaw następujący wiersz na początku pliku. Jeśli pracujesz w projekcie Visual Basic, zastąp ciąg "C#" ciągiem "VB".

    <#@ template language="C#" #>

  6. Dodaj odwołanie do pakietu NuGet System.CodeDom.

Zawartość szablonu czasu wykonywania

Dyrektywa szablonu

Zachowaj pierwszy wiersz szablonu, tak jak podczas tworzenia pliku:

<#@ template language="C#" #>

Parametr języka będzie zależeć od języka projektu.

Zwykła zawartość

Zmodyfikuj plik tt , aby zawierał tekst, który ma zostać wygenerowany przez aplikację. Na przykład:

<html><body>
<h1>Sales for January</h2>
<!-- table to be inserted here -->
This report is Company Confidential.
</body></html>

Osadzony kod programu

Kod programu można wstawić między elementami <# i #>. Na przykład:

<table>
    <# for (int i = 1; i <= 10; i++)
       { #>
         <tr><td>Test name <#= i #> </td>
             <td>Test value <#= i * i #> </td> </tr>
    <# } #>
 </table>

Zwróć uwagę, że instrukcje są wstawiane między wyrażeniami <# ... #> i są wstawiane między elementami <#= ... #>. Aby uzyskać więcej informacji, zobacz Pisanie szablonu tekstowego T4.

Korzystanie z szablonu

Kod utworzony na podstawie szablonu

Podczas zapisywania pliku tt jest generowany plik zależny .cs lub .vb . Aby wyświetlić ten plik w Eksplorator rozwiązań, rozwiń węzeł pliku tt. W projekcie Visual Basic najpierw wybierz pozycję Pokaż wszystkie pliki na pasku narzędzi Eksplorator rozwiązań.

Zwróć uwagę, że plik zależny zawiera klasę częściową zawierającą metodę o nazwie TransformText(). Tę metodę można wywołać z poziomu aplikacji.

Generowanie tekstu w czasie wykonywania

W kodzie aplikacji możesz wygenerować zawartość szablonu przy użyciu wywołania w następujący sposób:

MyWebPage page = new MyWebPage();
String pageContent = page.TransformText();
System.IO.File.WriteAllText("outputPage.html", pageContent);

Aby umieścić wygenerowaną klasę w określonej przestrzeni nazw, ustaw właściwość Niestandardowa przestrzeń nazw narzędzi pliku szablonu tekstowego.

Debugowanie szablonów tekstu środowiska uruchomieniowego

Debugowanie i testowanie szablonów tekstu środowiska uruchomieniowego w taki sam sposób jak zwykły kod.

Punkt przerwania można ustawić w szablonie tekstowym. Jeśli uruchomisz aplikację w trybie debugowania z poziomu programu Visual Studio, możesz przejść przez kod i ocenić wyrażenia zegarka w zwykły sposób.

Przekazywanie parametrów w konstruktorze

Zazwyczaj szablon musi importować dane z innych części aplikacji. Aby ułatwić ten proces, kod utworzony przez szablon jest klasą częściową. Możesz utworzyć inną część tej samej klasy w innym pliku w projekcie. Ten plik może zawierać konstruktor z parametrami, właściwościami i funkcjami, do których można uzyskać dostęp zarówno za pomocą kodu osadzonego w szablonie, jak i pozostałej części aplikacji.

Można na przykład utworzyć oddzielny plik MyWebPageCode.cs:

partial class MyWebPage
{
    private MyData m_data;
    public MyWebPage(MyData data) { this.m_data = data; }}

W pliku szablonu MyWebPage.tt można napisać:

<h2>Sales figures</h2>
<table>
<# foreach (MyDataItem item in m_data.Items)
   // m_data is declared in MyWebPageCode.cs
   { #>
      <tr><td> <#= item.Name #> </td>
          <td> <#= item.Value #> </td></tr>
<# } // end of foreach
#>
</table>

Aby użyć tego szablonu w aplikacji:

MyData data = ...;
MyWebPage page = new MyWebPage(data);
String pageContent = page.TransformText();
System.IO.File.WriteAllText("outputPage.html", pageContent);

Parametry konstruktora w Visual Basic

W języku Visual Basic oddzielny plik MyWebPageCode.vb zawiera:

Namespace My.Templates
  Partial Public Class MyWebPage
    Private m_data As MyData
    Public Sub New(ByVal data As MyData)
      m_data = data
    End Sub
  End Class
End Namespace

Plik szablonu może zawierać:

<#@ template language="VB" #>
<html><body>
<h1>Sales for January</h2>
<table>
<#
    For Each item In m_data.Items
#>
    <tr><td>Test name <#= item.Name #> </td>
      <td>Test value <#= item.Value #> </td></tr>
<#
    Next
#>
</table>
This report is Company Confidential.
</body></html>

Szablon może być wywoływany przez przekazanie parametru w konstruktorze:

Dim data = New My.Templates.MyData
    ' Add data values here ....
Dim page = New My.Templates.MyWebPage(data)
Dim pageContent = page.TransformText()
System.IO.File.WriteAllText("outputPage.html", pageContent)

Przekazywanie danych we właściwościach szablonu

Alternatywnym sposobem przekazywania danych do szablonu jest dodanie właściwości publicznych do klasy szablonu w częściowej definicji klasy. Aplikacja może ustawić właściwości przed wywołaniem TransformText()metody .

Pola można również dodać do klasy szablonu w definicji częściowej. Dzięki temu można przekazywać dane między kolejnymi wykonaniami szablonu.

Używanie klas częściowych dla kodu

Wielu deweloperów woli unikać pisania dużych treści kodu w szablonach. Zamiast tego można zdefiniować metody w klasie częściowej, która ma taką samą nazwę jak plik szablonu. Wywołaj te metody z szablonu. W ten sposób szablon pokazuje bardziej wyraźnie, jak będzie wyglądał docelowy ciąg wyjściowy. Dyskusje na temat wyglądu wyniku można oddzielić od logiki tworzenia wyświetlanych danych.

Zestawy i odwołania

Jeśli chcesz, aby kod szablonu odwołył się do platformy .NET lub innego zestawu, takiego jak System.Xml.dll, dodaj go do odwołań projektu w zwykły sposób.

Jeśli chcesz zaimportować przestrzeń nazw w taki sam sposób jak using instrukcja, możesz to zrobić za import pomocą dyrektywy :

<#@ import namespace="System.Xml" #>

Dyrektywy te należy umieścić na początku pliku bezpośrednio po <#@template dyrektywie.

Zawartość udostępniona

Jeśli masz tekst udostępniony między kilkoma szablonami, możesz umieścić go w osobnym pliku i dołączyć go do każdego pliku, w którym powinien się pojawić:

<#@include file="CommonHeader.txt" #>

Dołączona zawartość może zawierać dowolną kombinację kodu programu i zwykłego tekstu oraz może zawierać inne dyrektywy include i inne dyrektywy.

Dyrektywa include może być używana w dowolnym miejscu w tekście pliku szablonu lub dołączonego pliku.

Dziedziczenie między szablonami tekstu w czasie wykonywania

Zawartość między szablonami czasu wykonywania można udostępniać, pisząc szablon klasy bazowej, który może być abstrakcyjny. inherits Użyj parametru <@#template#> dyrektywy, aby odwołać się do innej klasy szablonu środowiska uruchomieniowego.

Wzorzec dziedziczenia: fragmenty w metodach podstawowych

W wzorcu użytym w poniższym przykładzie zwróć uwagę na następujące kwestie:

  • Klasa SharedFragments bazowa definiuje metody w blokach <#+ ... #>funkcji klasy .

  • Klasa bazowa nie zawiera wolnego tekstu. Zamiast tego wszystkie bloki tekstowe występują wewnątrz metod funkcji klasy.

  • Klasa pochodna wywołuje metody zdefiniowane w pliku SharedFragments.

  • Aplikacja wywołuje metodę TextTransform() klasy pochodnej, ale nie przekształca klasy SharedFragmentsbazowej .

  • Zarówno podstawowe, jak i pochodne klasy to szablony tekstowe środowiska uruchomieniowego; oznacza to, że właściwość Custom Tool jest ustawiona na TextTemplatingFilePreprocessor.

SharedFragments.tt:

<#@ template language="C#" #>
<#+
protected void SharedText(int n)
{
#>
   Shared Text <#= n #>
<#+
}
// Insert more methods here if required.
#>

MyTextTemplate1.tt:

<#@ template language="C#" inherits="SharedFragments" #>
begin 1
   <# SharedText(2); #>
end 1

MyProgram.cs:

...
MyTextTemplate1 t1  = new MyTextTemplate1();
string result = t1.TransformText();
Console.WriteLine(result);

Wynikowe dane wyjściowe:

begin 1
    Shared Text 2
end 1

Wzorzec dziedziczenia: tekst w treści podstawowej

W tym alternatywnym podejściu do korzystania z dziedziczenia szablonu większość tekstu jest definiowana w szablonie podstawowym. Szablony pochodne udostępniają dane i fragmenty tekstu, które mieszczą się w zawartości podstawowej.

AbstractBaseTemplate1.tt:

<#@ template language="C#" #>

Here is the description for this derived template:
  <#= this.Description #>

Here is the fragment specific to this derived template:
<#
  this.PushIndent("  ");
  SpecificFragment(42);
  this.PopIndent();
#>
End of common template.
<#+
  // State set by derived class before calling TextTransform:
  protected string Description = "";
  // 'abstract' method to be defined in derived classes:
  protected virtual void SpecificFragment(int n) { }
#>

DerivedTemplate1.tt:

<#@ template language="C#" inherits="AbstractBaseTemplate1" #>
<#
  // Set the base template properties:
  base.Description = "Description for this derived class";

  // Run the base template:
  base.TransformText();

#>
End material for DerivedTemplate1.

<#+
// Provide a fragment specific to this derived template:

protected override void SpecificFragment(int n)
{
#>
   Specific to DerivedTemplate1 : <#= n #>
<#+
}
#>

Kod aplikacji:

...
DerivedTemplate1 t1 = new DerivedTemplate1();
string result = t1.TransformText();
Console.WriteLine(result);

Wynikowe dane wyjściowe:

Here is the description for this derived template:
  Description for this derived class

Here is the fragment specific to this derived template:
     Specific to DerivedTemplate1 : 42
End of common template.
End material for DerivedTemplate1.

Szablony czasu projektowania: jeśli chcesz użyć szablonu do wygenerowania kodu, który staje się częścią aplikacji, zobacz Generowanie kodu w czasie projektowania przy użyciu szablonów tekstowych T4.

Szablony czasu wykonywania mogą być używane w dowolnej aplikacji, w której szablony i ich zawartość są określane w czasie kompilacji. Jeśli jednak chcesz napisać rozszerzenie programu Visual Studio, które generuje tekst z szablonów, które zmieniają się w czasie wykonywania, zobacz Wywoływanie przekształcenia tekstu w rozszerzeniu programu VS.