15 сентября 2012 г.

Шаблоны T4 в Visual Studio: Расширенные возможности


В прошлой статье мы познакомились с механизмом генерации текста на основе шаблонов, который предлагает нам Visual Studio и .NET Framework под именем Т4. Мы рассмотрели один из самых распространенных сценариев использования шаблонов – генерация письма, с передачей параметров в шаблон. В этой статье мы обсудим другие функциональные возможности шаблонов Т4, которые могут сделать вашу работу с ними еще более удобной.

1) Использование функций и классов из других пространств имен. По умолчанию, шаблон и его класс-оболочка находятся в пространстве имен, которое соответствует имени папки(вы можете его изменить, указав в свойствах файлах Custom Tool Namespace). Если вы хотите использовать класс из другого пространства имен, используйте директиву Import:
Например у нас есть Helper класс, и мы хотим использовать его метод внутри нашего шаблона:
   1:  namespace T4_Test.Utils
   2:  {
   3:      public class Helper
   4:      {
   5:          public static int GetSum(int firstNumber, int secondNumber)
   6:          {
   7:              return firstNumber + secondNumber;
   8:          }
   9:      }
  10:  }
В код необходимо добавить директиву Import c именем нужного пространства имен, модифицировав его следующим образом:
   1:  <#@ template language="C#" #>
   2:   
   3:  <#@ Import Namespace="T4_Test.Utils" #>
   4:   
   5:  Your bill: <#= Helper.GetSum(1, 2)  #>
Похожим способом вы можете использовать любые методы и классы, достаточно лишь зарегистрировать пространство имен.
2) Объявление вспомогательных функций внутри самого шаблона. Перепишем пример выше, перенеся метод GetSum из вспомогательного класса в код шаблона:
   1:  <#@ template language="C#" #>
   2:  <#@ Import Namespace="T4_Test.Console.Utils" #>
   3:   
   4:  Your bill: <#= GetSum(1, 2)  #>
   5:   
   6:  <#+
   7:          int GetSum(int firstNumber, int secondNumber)
   8:          {
   9:              return firstNumber + secondNumber;
  10:          }
  11:  #>
3) Вложенность шаблонов. Внутри шаблона можно с легкостью вызывать другой шаблон (или точнее сказать отображать другой шаблон, так как данные в него при этом передать не получится, что на мой взгляд одно из основных недостатков данного способа вызова, решение этой проблемы будет описано далее).
Рассмотрим наш старый сценарий с письмами: наверняка в каждое письмо вы захотите поместить логотип вашей компании сверху и текст "Copyright" снизу. С этой целью мы определим два шаблона, которые будут определять заголовок и подвал письма соответственно:
HeaderTemplate.tt –
   1:  <#@ template debug="false" hostspecific="false" language="C#" #>
   2:  <#@ output extension=".txt" #>
   3:   
   4:  My Site Name
и FooterTemplate.tt –
   1:  <#@ template debug="false" hostspecific="false" language="C#" #>
   2:  <#@ output extension=".txt" #>
   3:   
   4:  Copyright 2012
Теперь изменим шаблон письма, так чтобы он использовал созданные нами шаблоны. Шаблон заголовка должен идти самым первым (но после главных директив шаблона), а шаблон подвала, соответственно последним:
   1:  <#@ template language="C#" #>
   2:  <#@ Parameter Name="UserName" Type="System.String" #>
   3:   
   4:  <#@ Include File="HeaderTemplate.tt" #>
   5:  Hello, <#= this.UserName #>
   6:  Welcome to our web-site!
   7:  <#= DateTime.Now #>
   8:  <#@ Include File="FooterTemplate.tt" #>
Директивы Include встраивают текст, указанных шаблонов, в место своего объявления.
4) Легкость отладки. Безусловно, это будет огромным преимуществом, по сравнению с тем же XSLT, внутри шаблона можно спокойно расставить точки остановки и в реалтайме пройти все его шаги. Также, Visual Studio позволит вам зайти внутрь шаблона, при прохождении в режиме дебага кода его вызова.
5) Наследование шаблонов. Наконец, мы добрались, наверное, до самого мощного средства, которое предоставляет разработчикам среда шаблонов Т4. Наследование шаблонов решает проблему передачи данных между шаблонами и, соответственно, гибкого использования многократно повторяющейся разметки шаблона.
Рассмотрим следующий сценарий: используя пример с письмами, предположим, что в каждом письме присутствует имя пользователя на одном и том же месте. В таком случае будет целесообразно вынести эту надпись в базовый шаблон. Но, поскольку, имя пользователя – это динамический параметр, его необходимо в базовый шаблон передавать.
Первым делом определим базовый шаблон:
BaseTemplate.tt –
   1:  <#@ template language="C#" #>
   2:   
   3:  <#+
   4:      protected void ShowName(string name)
   5:      {
   6:  #>
   7:         Hello, <#= name #>
   8:  <#+
   9:      }
  10:  #>
Здесь мы объявили некоторое подобие функции, которая будет доступна всем наследникам данного шаблона. В данную функцию передается имя пользователя, как параметр, который будет отображен в результирующем тексте, во время выполнения шаблона. При необходимости, этот класс можно сделать абстрактным.
Родительский шаблон и его наследник связываются при помощи директивы:
   1:  <#@ template language="C#" Inherits="....." #>
Объявим наследника следующим образом:
   1:  <#@ template language="C#" Inherits="BaseTemplate" #>
   2:  <#@ Parameter Name="UserName" Type="System.String" #>
   3:   
   4:  <#
   5:      ShowName(this.UserName);
   6:  #>
   7:   
   8:  Welcome to our web-site! 
   9:   
  10:  <#= DateTime.Now #>
  11:   
  12:  <#@ Include File="FooterTemplate.tt" #>
Ключевым в этом коде является атрибут Inherits, который указывает от какого шаблона наследуется наше письмо. Теперь мы можем вызвать метод базового письма, передав туда необходимое значение.
Если вы посмотрите на код класса, который сгенерировался в результате, то увидите, что класс-оболочка шаблона MessageTemplate просто унаследован от класса BaseTemplate.
Таким образом, мы познакомились с перечнем основных функций, которые предоставляет .NET разработчикам среда генерации шаблонов T4. Различно комбинируя описанные выше приемы вы сможете достичь любого желаемого эффекта, разработав шаблоны для генерации необходимых текстов. Использование среды .NET и языка программирования C# в основе данного механизма позволит вам разработать грамотную, объектно-ориентированную среду генерации данных.
Напомню вам, что в этой статье мы рассмотрели генерация шаблонов Т4 в режиме «TextTemplatingFilePreprocessor». Данный режим обеспечивает возможность построения шаблона, во время выполнения программы. Однако, также существует другой режим работы Т4, который позволяет генерировать программный код в момент разработки. С этим режимом мы познакомимся в следующей статье, а заодно узнаем, где такой сценарий может быть применен на практике.

Комментариев нет:

Отправить комментарий