Основные усилия программистов при реализации и сопровождении программного проекта уходят на расширение, модификацию и исправление программного кода. На первоначальную разработку программы затрачивается относительно немного времени. Поэтому разработчики стараются внедрять решения, которые удобны и эффективны для последующих модификаций и дополнений. Легкость разработки первоначальной версии приложения не является главным приоритетом.
Наглядным и удобным способом генерации кода является применение текстовых шаблонов. Техники применения шаблонов являются в большей степени декларативными способами генерации текста. Шаблон уже предоставляет макет кода в естественном для программиста виде. Неизменяемая часть кода уже заложена в шаблоне в том же самом виде, что и готовый сгенерированный код. С помощью специальных команд, инструкций, выполнения программного кода выводятся те части шаблона, которые не являются статическими, а меняются в зависимости от метаданных и настроек. Текстовые шаблоны позволяют упрощать генерацию кода. Если нужно изменить создаваемый код, то не потребуется разбираться в программе, генерирующей код, а достаточно изменить наглядный шаблон. Однако шаблоны эффективно применимы только тогда, когда повторяющийся код встречается часто во многих участках приложения, и его объем достаточно большой.
Технология T4 (Text Templating Transformation Toolkit) является инструментом генерации кода на основе шаблонов. Она включена в Visual Studio 2008 и Visual Studio 2010. А в Visual Studio 2005 она доступна при установке DSL (Domain-Specific Language) и GAT(Guidance Automation Toolkit). С помощью текстовых шаблонов можно сгенерировать все виды текстовой информации, так называемых артефактов. Это может быть программный код на C#, VB.Net, разметка HTML, запросы SQL, документация и любая другая текстовая информация. Технологию T4 можно применять как для генерации отдельных файлов, так и крупных приложений.
Для создания простого шаблона T4 надо выполнить следующие шаги:
<#@ template debug="false" language="C#" #>
<#@ output extension=".cs" #>
<# string[] vars = new string [] {"A", "B", "C"}; #>
class MyClass {
<#
foreach (string variable in vars)
{ #>
private int <#= variable #> = 0;
<# } #>
}
После этого шага под файлом шаблона появится файл кода на C#, как на следующем рисунке.
(рис 4.1) Файл кода, сгенерированного на основе шаблона T4
Мы уже рассматривали этот пример во второй лекции. Если посмотрим на код сгенерированного файла MyClass.cs, то он будет таким.
class MyClass {
private int A = 0;
private int B = 0;
private int C = 0;
}
Шаблонные файлы имеют синтаксис, похожий на страницы ASP.Net. Встроенный редактор T4 не выполняет даже простейшую
В шаблонах T4 применяются следующие виды блоков: <#@ #> - для директив, <# #> - для блоков кода, <#+ #> - для блоков вспомогательных методов, <#= #> - блоков выражений. Все, что не входит в вышеперечисленные блоки, считается блоками текста. Они не обрамляются никакими тегами. Что мы видим в блоках текста, то будет и отображено без изменений в сгенерированном коде.
Директивы являются элементами, которые указывают, как именно должен обрабатываться шаблон.
Блоки кода вида <#...#> содержат код на C# или Visual Basic. В ходе своей работы этот код может выводить текст в файл результата шаблона.
public class MyClass
{
<#
for (int i=0;i < 2;i++)
{
#>
public void DoAction()
{
}
<#
}
#>
}
Результатом работы вышеуказанного шаблона будет следующий код:
public class MyClass
{
public void DoAction()
{
}
public void DoAction()
{
}
}
Этот сгенерированный код некорректен, так как в классе содержатся два метода с одним именем и сигнатурой. Но сейчас это не имеет большого значения, важен сам факт вывода кода.
Блоки выражений <#=...#> служат для записи результатов выражений непосредственно в текст.
public class MyClass
{
<#
for (int i=0;i < 2;i++)
{
#>
public void DoAction<#=i#>()
{
}
<#
}
#>
}
Здесь выражение <#=i#> подставляет значение i в текст шаблона. Значение i меняется циклически. Результатом работы шаблона будет следующий код.
public class MyClass
{
public void DoAction0()
{
}
public void DoAction1()
{
}
}
Разумеется, выражение может выглядеть гораздо сложнее. Альтернативой блокам выражений является применение методов Write и WriteLine в блоке кода.
public class MyClass
{
<#
for (int i=0;i < 2;i++)
{
WriteLine("\tpublic void DoAction" + i + "()");
#>
{
}
<#
}
#>
}
Здесь символ "\t" означает табуляцию. Результат будет тем же, что и в предыдущем примере.
Блоки вида <#+…#> позволяют добавлять вспомогательные методы (функции) в шаблон. Они могут впоследствии вызываться изнутри шаблона, где это необходимо. Рассмотрим следующий пример.
public class MyClass
{
<#
for (int i=0;i < 2;i++)
{
#>
public void <#= CreateFunctionName(i)#>()
{
}
<#
}
#>
}
<#+ public string CreateFunctionName(int counter)
{
string result = "";
switch (counter)
{
case 0:
result = "DoActionOne";
break;
case 1:
result = "DoActionTwo";
break;
}
return result;
}
#>
В цикле вызывается метод CreateFunctionName. Он объявляется в блоке вспомогательных выражений между тегами <#+ и #>.
Вспомогательные методы обязательно должны находиться в конце шаблона. Блок вспомогательных методов может содержать также блоки выражений, кода, текста - как и в самом шаблоне. Результатом работы примера будет следующее:
public class MyClass
{
public void DoActionOne()
{
}
public void DoActionTwo()
{
}
}
Директивы служат для установки правил обработки конкретного файла шаблона. Синтаксис директив имеет следующий формат:
<#@ ИмяДирективы [ИмяАттрибута = "ЗначениеАттрибута"] ... #>
Каждая из директив имеет свое предназначение. Имя директивы указывается один раз в самом начале и принимает одно из следующих значений:
Также можно создавать пользовательские директивы. Секция [ИмяАттрибута = "ЗначениеАттрибута"] может указываться один и более раз. Давайте рассмотрим директивы поподробнее.
Директива Template указывает среде правила обработки файла шаблона и имеет следующий формат:
<#@ template [language="VB"] [hostspecific="true"] [debug="true"] [inherits="templateBaseClass"]
[culture="code"] [compilerOptions="options"] #>
Все атрибуты являются необязательными. Параметр language указывает язык, на котором пишется код в шаблоне. Может принимать значения "C#" или "VB". Атрибут compilerOptions определяет условия компиляции. Атрибут culture указывает на культурную среду. Атрибут debug указывает, нужна отладка или нет. С помощью атрибута inherits можно указать, что код файла шаблона может наследоваться от другого класса, который, в свою очередь, тоже может быть сгенерирован из другого шаблона.
Установка атрибута hostspecific в значение true позволяет коду шаблона получить доступ к API Visual Studio. В коде шаблона становится возможным указывать Host, например, к дате и времени:
<#= Host.CurrentDateTime #>
Рассмотрим следующую директиву
<#@ template language="С#" hostspecific="true" debug="true" #>
Эта директива указывает, что код шаблона будет реализован на языке C# и нужен доступ к API Visual Studio. Включается отладчик для поиска и устранения ошибок в шаблоне.
Директива parameter позволяет указывать параметры, которые могут передаваться в шаблон извне, и имеет следующий формат:
<#@ parameter type="ИмяТипа" name="Имя параметра" #>
Директива parameter доступна только начиная с Visual Studio 2010/.NET 4. Однако, во всех версиях Visual Studio можно передавать параметры в шаблон добавлением значений в класс CallContext.
Директива parameter имеет обязательные атрибуты type и name. Атрибут type передает название типа параметра. При этом должно указываться полное имя типа, например System.string, а не string. Этот пример передает строковый параметр TableName:
<#@ parameter type="System.string" name="TableName"#>
После включения параметров их можно использовать внутри шаблона как переменные.
Директива output позволяет указать расширение и кодировку выходного файла. Расширение можно указать любое, по умолчанию принимается значение ".cs". Кодировка может принимать такие значения, как "utf-8", "us-ascii", " и т.д. Имеет следующий формат.
<#@ output extension=".расширение" [encoding="обозначениеКодировки"] #>
Директива assembly позволяет загрузить сборку и применять классы и методы этой сборки в шаблоне. Если нужна сборка из состава .Net, то можно просто указать имя сборки. Для других сборок надо указать полный путь к файлу сборки. Формат директивы assembly следующий:
<#@ assembly name="[ИмяСборки|ПутьКФайлу]" #>
Формат директивы import:
<#@ import namespace="ПространствоИмен" #>
Эта директива позволяет импортировать пространства имен. В коде шаблона можно будет использовать простые имена классов вместо полных имен.
Формат директивы include:
<#@ include file="filePath" #>
Эта директива позволяет включить в шаблон содержимое другого файла. ".tt", например ".txt" или ".t4". Если в двух файлах шаблона есть схожие участки, можно в отдельном файле хранить общую часть шаблонов. А в оригинальных файлах директивы включения надо поставить вместо повторяющихся участков кода. Позже, при необходимости можно менять только содержимое включаемого файла.
В шаблонах можно считывать метаданные из XML-файлов и генерировать файлы. Допустим, нам надо создать код объявлений констант. Создадим файл variables.xml и добавим его в проект, заполнив таким содержимым:
<?xml version="1.0" encoding="utf-8" ?>
<constants>
<constant name="A" value="1"/>
<constant name="B" value="2"/>
<constant name="C" value="3"/>
<constant name="D" value="4"/>
</constants>
Следующий шаблон считывает данные из файла метаданных и генерирует код:
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Xml" #>
<#@ import namespace="System.Xml" #>
<#
XmlDocument reader = new XmlDocument();
reader.Load(this.Host.ResolvePath("variables.xml"));
XmlElement elem =reader.DocumentElement;
for (int i = 0; i < elem.ChildNodes.Count; i++)
{
XmlElement elemField = (XmlElement)elem.ChildNodes[i];
#>
const int <#=elemField.GetAttribute("name")#> = <#=elemField.GetAttribute("value")#>;
<#
}
#>
Установка параметра hostspecific в значение true позволяет применить выражение this.Host.ResolvePath("variables.xml"). Директива assembly дает возможность использовать в шаблоне классы для работы с XML. Директива import позволяет использовать сокращенные имена классов, например можно писать XmlDocument вместо System.Xml.XmlDocument. Параметр extension директивы output устанавливает расширение выходного файла. Также внутри шаблонного текста используются блоки выражений <#= #>. Результат работы шаблона будет таким:
const int A = 1;
const int B = 2;
const int C = 3;
const int D = 4;
Механизм T4 выполняет генерацию в два шага. На первом шаге происходит разбор шаблона и генерируется класс GeneratedTextTransformation, который содержит метод TransformText. Выполняется компиляция этого класса в сборку. На втором шаге создается объект данного класса и запускается метод TransformText, который и формирует текст. Другими словами, на первом шаге из шаблона генерируется программа, на втором шаге эта программа запускается и генерирует выходной файл.
При генерации кода возникает необходимость автоматической установки в нем отступов. В следующем примере в первых двух строках и последней строке нет отступа, а в начало остальных строк вставлена табуляция.
public class MyClass
{
public void DoAction0()
{
}
public void DoAction1()
{
}
}
Методы PushIndent, PopIndent, ClearIndent позволяют гибко контролировать отступы в генерируемом тексте. Метод PushIndent устанавливает отступ для следующих за ним строк. К началу каждой строки генерируемого текста добавляется символьная строка. Ее содержимое передается в этот метод. Отступом может быть не только табуляция, но и любая последовательность символов. Метод PushIndent может вызываться много раз. После каждого вызова метода строка символов добавляется в стек. Метод PopIndent убирает последний добавленный отступ. Метод ClearIndent очищает стек отступов.
Рассмотрим пример, при котором нам надо отобразить следующую таблицу из четырех ячеек в формате HTML:
<table>
<tr>
<td>1</td>
<td>2</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
</tr>
</table>
Шаблон T4, формирующий HTML-разметку:
<#@ template language="C#" #>
<#@ output extension=".html" #>
<#
WriteLine("<table>");
PushIndent("\t");
WriteLine("<tr>");
PushIndent("\t");
WriteLine("<td>1</td>");
WriteLine("<td>2</td>");
PopIndent();
WriteLine("</tr>");
WriteLine("<tr>");
PushIndent("\t");
WriteLine("<td>3</td>");
WriteLine("<td>4</td>");
PopIndent();
WriteLine("</tr>");
ClearIndent();
WriteLine("</table>");
#>
Обратите внимание, что нет необходимости добавлять табуляцию в каждом вызове метода WriteLine. Табуляция добавляется в стек отступов в методе PushIndent.
Модель генерируемой области может быть заложена в базе данных, текстовом файле, XML-файле, файле Visio, а также в диаграммах UML и языках
Генерация кода из модели UML представляется очень удобным решением. На практике в большинстве случаев модель UML плохо связана с программным кодом, документацией, и т.д. Являясь средством проектирования и визуального представления, диаграммы UML как бы живут своей жизнью. При внедрении изменений часто изменения вносятся отдельно в диаграмму и отдельно в программный код. Применение технологии T4 для генерации файлов из модели UML может оказаться эффективным. При изменении схемы UML надо только заново сгенерировать файлы.
Существуют три способа генерации файлов из модели UML с применением шаблонов T4:
DSL (Domain-Specific Language), или язык предметной области, является нотацией, чаще всего графической, разработанной для конкретных, определенных целей. Для каждой специфической задачи создается язык
Есть несколько способов расширить функциональность T4:
Шаблон T4 является, по сути дела, текстом. И его можно хранить в файле или базе данных. Используя набор разных шаблонов, и применяя включение шаблонов, можно строить сложные схемы генерации кода. Технология Т4 может расширяться путем добавления новых возможностей. Наиболее эффективно применение шаблонов в тех случаях, когда большой объем сгенерированного кода остается неизменным и в генератор передается мало параметров.
Технология T4 имеет множество ограничений, которые, однако, могут быть преодолены ее встроенной расширяемостью и разнообразными приемами. Поведение директив может отличаться на разных хостах, а также может быть изменено созданием пользовательских хостов. Также, синтаксис шаблонов T4 могут расширять пользовательские директивы.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.