Поделиться через


Создание текста во время выполнения с помощью предварительно обработанных текстовых шаблонов T4

С помощью предварительно обработанных текстовых шаблонов Visual Studio можно создавать в приложении текстовые строки во время выполнения. На компьютере, на котором выполняется приложение, не обязательно должна быть установлена система Visual Studio. Предварительно обработанные шаблоны иногда называются "текстовые шаблоны времени выполнения".

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

Например, следующий шаблон можно использовать в приложении, создающем 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>

Обратите внимание, что шаблон — это страница HTML, в которой переменные части были заменены программным кодом. Начать создание такой страницы можно с написания статического прототипа страницы HTML. Затем можно заменить таблицу и другие переменные части программным кодом, который генерирует содержимое, варьирующееся от случая к случаю.

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

Создание текстового шаблона времени выполнения в любом приложении

Создание текстового шаблона времени выполнения

  1. В обозревателе решений щелкните правой кнопкой мыши проект, выберите команду Добавить, а затем Создать элемент.

  2. В диалоговом окне Добавление нового элемента выберите пункт Предварительно преобразованный текстовый шаблон. (В Visual Basic см. в разделе Common Items\General.)

  3. Введите имя файла шаблона.

    Примечание

    Имя файла шаблона будет использоваться как имя класса в сгенерированном коде.Поэтому оно не должно содержать пробелов и знаков препинания.

  4. Нажмите кнопку Добавить.

    Будет создан новый файл с расширением .tt. Его свойство Специальный инструмент будет иметь значение TextTemplatingFilePreprocessor. Содержит следующую строку:

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

Преобразование существующего файла в шаблон времени выполнения

Удобный способ создания шаблона — преобразование имеющегося примера выходных данных. Например, если приложение будет генерировать HTML-файлы, можно начать с создания обычного HTML-файла. Убедитесь, что он правильно работает и его представление является верным. Затем включите его в проект Visual Studio и преобразуйте в шаблон.

Преобразование существующего текстового файла в шаблон времени выполнения

  1. Включите файл в проект Visual Studio. В обозревателе решений щелкните правой кнопкой мыши проект, выберите команду Добавить и щелкните Существующий элемент.

  2. Свойству Специальные инструменты этого файла присвойте значение TextTemplatingFilePreprocessor. В обозревателе решений щелкните правой кнопкой мыши файл и выберите команду Свойства.

    Примечание

    Если это свойство уже установлено, убедитесь, что оно имеет значение TextTemplatingFilePreprocessor, а не TextTemplatingFileGenerator.Так может случиться, если вы включили файл, уже имеющий расширение .tt.

  3. Измените расширение имени файла на .tt. Хотя этот шаг является необязательным, он позволяет избежать открытия файла в неподходящем редакторе.

  4. Удалите из основной части имени файла все пробелы и знаки препинания. Например, имя "My Web Page.tt" было бы неверным, а имя "MyWebPage.tt" годится. Имя файла будет использоваться как имя класса в сгенерированном коде.

  5. В начало файла вставьте следующую строку: Если вы работаете в проекте Visual Basic, замените "C#" на "VB".

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

Содержимое шаблона времени выполнения

Директива template

Сохраните первую строку шаблона в том виде, в каком она была при создании файла:

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

Параметр language будет зависеть от языка проекта.

Чистое содержимое

Отредактируйте файл .tt, чтобы он содержал только текст, который должно генерировать приложение. Пример.

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

Внедренный программный код

Программный код можно вставлять между тегами <# и #>. Пример.

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

<table>
<#
    For i As Integer = 1 To 10
#>
    <tr><td>Test name <#= i #> </td>
      <td>Test value <#= i*i #> </td></tr>
<#
    Next
#>
</table>

Обратите внимание, что инструкции вставляются между тегами <# ... #>, а выражения – между <#= ... #>. Дополнительные сведения см. в разделе Написание текстового шаблона T4.

Использование шаблона

Код, формируемый на основе шаблона

При сохранении файла .tt генерируется дочерний файл .cs или .vb. Чтобы просмотреть этот файл в обозревателе решений, разверните узел файла .tt. В проекте Visual Basic возможность развернуть этот узел появится после того, как вы щелкните Показать все файлы на панели инструментов обозревателя решений.

Заметьте, что этот дочерний файл содержит разделяемый класс, имеющий метод с именем TransformText(). Этот метод можно вызвать из приложения.

Генерирование текста во время выполнения

В коде приложения можно генерировать содержимое шаблона с использованием таких вызовов:

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

Чтобы поместить созданный класс в определенном пространстве имен, задайте значение для свойства Пространство имен специального инструмента в файле текстового шаблона.

Передача параметров в конструкторе

Обычно шаблон должен импортировать некоторые данные из других частей приложения. Чтобы облегчить эту задачу, генерируемый на основе шаблона код создается в виде разделяемого класса. Можно создать другую часть этого класса в другом файле проекта. Этот файл может содержать конструктор с параметрами, свойства и функции, доступные как из внедренного в шаблон кода, так и из остальной части приложения.

Например, можно создать отдельный файл MyWebPageCode.cs:

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

В файле шаблона MyWebPage.tt можно написать:

<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>

Использование этого шаблона в приложении

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

Параметры конструктора в Visual Basic

В Visual Basic отдельный файл MyWebPageCode.vb содержит следующее:

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

Файл шаблона может содержать:

<#@ 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>

Шаблон в этом случае вызывается передачей параметров в конструктор:

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)

Передача данных в свойства шаблона

Альтернативным способом передачи данных шаблону является добавление в класс шаблона открытых свойств в частичном определении класса. Перед вызовом метода TransformText() приложение может задать свойства.

Кроме того, в класс шаблонов можно добавить поля в виде частичного определения. В этом случае можно выполнять передачу данных между последовательными выполнениями шаблона.

Использование разделяемого класса для кода

Многие разработчики предпочитают не включать в шаблоны крупные фрагменты кода. Вместо этого определяются методы в разделяемом классе, имя которого совпадает с именем файла шаблона. Вызовите эти методы из шаблона. В этом случае в шаблоне лучше видно, как будет выглядеть целевая выходная строка. Обсуждения внешнего вида результата можно отделить от логики создания данных, которые отображаются в этом результате.

Сборки и ссылки

Если требуется, чтобы код шаблона ссылался на сборку .NET или другую сборку, такую как System.Xml.dll, нужно добавить ее в раздел Ссылки проекта обычным образом.

Если требуется импортировать пространство имен таким же образом, как это делается с использованием инструкции using, можно воспользоваться директивой import:

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

Эти директивы должны размещаться в начале файла, сразу за директивой <#@template.

Общее содержимое

Если имеется текст, который должен использоваться в нескольких шаблонах, можно разместить его в отдельном файле и включать в каждый файл, где он должен присутствовать:

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

Включаемое содержимое может содержать любое сочетание программного кода и обычного текста, а также другие директивы include и прочие директивы.

Директива include может использоваться в любой части текста файла шаблона или включаемого файла.

Наследование текстовых шаблонов времени выполнения

Можно настроить обмен содержимым между шаблонами времени выполнения, создав шаблон базового класса, который может быть абстрактным. Используйте параметр inherits директивы <@#template#>, чтобы создать ссылку на другой класс предварительно обработанных шаблонов.

Шаблон наследования: фрагменты в базовых методах

В шаблоне, использованном в следующем примере, обратите внимание на следующее:

  • Базовый класс SharedFragments определяет методы в составе блоков функций класса <#+ ... #>.

  • Базовый класс не содержит текста в свободной форме. Все его текстовые блоки размещены внутри методов функций класса.

  • Производный класс вызывает методы, определенные в базовом классе SharedFragments.

  • Приложение вызывает метод TextTransform() производного класса, но не преобразует базовый класс SharedFragments.

  • И базовый, и производный классы являются предварительно обработанными текстовыми шаблонами, т. е. свойству Специальный инструмент присвоено значение 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);

Полученные выходные данные:

begin 1
    Shared Text 2
end 1

Шаблон наследования: текст в основной части базового шаблона

Этот подход является альтернативой использованию наследования шаблонов и предполагает определение массива текста в базовом шаблоне. Производные шаблон предоставляют фрагменты данных и текста, которые вставляются в базовое содержимое.

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 #>
<#+
}
#>

Код приложения:

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

Полученные выходные данные:

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.

Важно!

Если используется версия Visual Studio до выпуска пакета обновления SP1 Beta, в выходных данных не отображается никакой текст производного шаблона, выводимый до вызова метода base.TransformTemplate().

Связанные разделы

Шаблоны времени разработки: если требуется использовать шаблон для генерирования кода, который станет частью приложения, см. раздел Создание кода во время разработки с помощью текстовых шаблонов T4.

Предварительно преобразованные шаблоны могут использоваться в любом приложении, в котором шаблоны и их содержимое определяются во время компиляции. Однако если требуется написать расширение Visual Studio, генерирующее текст из шаблонов, изменяющихся во время выполнения, см. раздел Вызов преобразования текста в расширении VS.

См. также

Основные понятия

Написание текстового шаблона T4

Другие ресурсы

Создание кода и текстовые шаблоны T4

Understanding T4: Preprocessed Text Templates by Oleg Sych

Журнал изменений

Дата

Журнал

Причина

Март 2011

В раздел о пользовательской настройке добавлены сведения о наследовании.

Улучшение информации.

Октябрь 2010

Добавлены примеры VB.

Улучшение информации.