Подтвердить что ты не робот

Создание шаблонов T4 во время выполнения (время сборки)?

Мы создаем внутреннее приложение, которое должно генерировать HTML файлы для загрузки в списки eBay. Мы стремимся использовать механизм шаблонов для генерации HTML файлов на основе предварительно заданных баз данных и статических полей. Шаблон также должен иметь логические возможности (if-then, foreach и т.д.).

Мы посмотрели на T4, и он выглядит идеально, но мы ничего не видим о том, есть ли у него возможности, которые будут использоваться во время выполнения, чтобы пользователь мог создать шаблон T4, а затем приложение может "скомпилировать", он и сгенерирует окончательный HTML файл. Возможно ли это и как?

Если нет, есть ли другие рамки, над которыми мы должны смотреть, которые имеют все эти возможности?

4b9b3361

Ответ 1

У меня есть аналогичный набор классов, который я использую для этого, встраивание шаблонного текста в программное обеспечение.

В основном, он работает как старый ASP, вы окружаете код С# в блоках <%...%>, и вы можете генерировать результаты с помощью <%= expression %>.

Вы можете передать один объект в код шаблона, который, конечно, может быть любым типом объекта, который вам нравится, или просто массив параметров. Вы также можете ссылаться на свои собственные сборки, если вы хотите выполнить собственный код.

Вот как выглядел бы излучение класса:

<%
var parameters = (string[])data;
var namespaceName = parameters[0];
var className = parameters[1];
%>
namespace <%= namespaceName %>
{
    public class <%= className %>
    {
    }
}

Вы можете, конечно, перебирать вещи:

<% foreach (var parameter in parameters) { %>
<%= parameter %>
<% } %>

и введите код в if-blocks и т.д.

Библиотека классов выпущена на CodePlex здесь:

а также NuGet.

Проект поставляется с примерами, загружает источник или просматривает его в Интернете.

Чтобы ответить на вопросы по электронной почте, также здесь, чтобы другие могли видеть:

  • Все типы кода С#, которые вписываются в вызов метода, могут быть скомпилированы в шаблоне. Он работает с обычным кодом С# 3.5, со всем, что означает, нет никаких искусственных ограничений. Единственное, что нужно знать, это то, что любой код if, while, foreach и т.д., Содержащий код шаблона для emit, должен использовать фигурные скобки, вы не можете сделать однострочный блок if-then type. См. Ниже ограничение метода.
  • Параметр data соответствует тому, что было передано в качестве параметра метода .Generate(x) из вашего приложения, и имеет тот же тип. Если вы передадите объект, определенный в ваших собственных библиотеках классов, вам нужно добавить ссылку на код шаблона, чтобы правильно его получить. (<%@ reference your.class.library.dll %>)
  • Если вы повторно используете скомпилированный шаблон, он по сути будет только вызовом метода для класса, при фактическом вызове .Generate() никаких дополнительных накладных расходов не будет. Если вы не вызываете .Compile() самостоятельно, первый вызов .Generate() позаботится об этом. Также обратите внимание, что код запускается в отдельном домене приложения, поэтому есть небольшая служебная информация, связанная с копированием параметра и результатом взад и вперед. Код, однако, работает с нормальной скоростью кода JITted.NET.

Пример if-блока:

<% if (a == b) { %>
This will only be output if a==b.
<% } %>

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

<%
    if (a == b)
    {
%>
This will only be output if a==b.
<%
    }
%>

Отметьте, что все части кода, отличные от кода шаблона, будут в значительной степени выводиться как есть, что означает, что будут выведены вкладки и такие последующие блоки %>.

Существует один предел, весь написанный вами код должен вписываться в один вызов метода.

Позвольте мне объяснить.

Как работает механизм шаблонов, он создает файл .cs и передает его компилятору С#, этот файл .cs грубо выглядит следующим образом:

using directives

namespace SomeNamespace
{
    public class SomeClass
    {
        public string Render(object data)
        {
            ... all your code goes here
        }
    }
}

Это означает, что вы не можете определять новые классы, новые методы, поля на уровне классов и т.д.

Однако вы можете использовать анонимных делегатов для создания внутренних функций. Например, если вам нужен единый способ форматирования дат:

Func<DateTime, string> date2str = delegate(DateTime dt)
{
    return dt.ToString("G");
};

то вы можете просто использовать это в остальной части кода шаблона:

<%= date2str(DateTime.Now) %>

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

Изменить 23.04.2011: Исправлены ссылки на проект CodePlex.

Ответ 2

Если вы можете использовать Visual Studio 2010 для создания и редактирования шаблонов, то вы можете использовать предварительно скомпилированные шаблоны, которые были разработаны именно для этого сценария и поддерживаются в Microsoft.

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

http://www.olegsych.com/2009/09/t4-preprocessed-text-templates/

Ответ 3

Сборка, которая реализует преобразование текста T4, - это Microsoft.VisualStudio.TextTemplating.dll, которая поставляется с Visual Studio.

Если вы хотите начать с первых принципов, вам нужно реализовать Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost и передать его реализацию в качестве аргумента для Microsoft.VisualStudio.TextTemplating.Engine.ProcessTemplate(), который будет выполнять преобразование.

Это дает вам большую гибкость, чем вызов TextTransform.exe.

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

Распространение этой сборки позволит избежать необходимости установки Visual Studio.

Ответ 4

Шаблоны T4 могут быть скомпилированы с помощью инструмента командной строки TextTransform.exe. Вы может заставить ваше приложение создать файл .tt, а затем вызвать TextTransform.exe для генерации вывода.

Ответ 5

Полностью можно использовать T4 во время выполнения.

Microsoft действительно не поддерживает этот сценарий разумным способом в .NET 3.5. Похоже, что .NET 4.0 получит лучшую поддержку от Microsoft.

Mono предоставляет некоторую поддержку для этого сценария в .NET 3.5.

Я успешно реализовал эту концепцию с .NET 3.5 с помощью реализации Mono T4, но решение этой проблемы для .NET 3.5 для решения этой проблемы потребует больше усилий, чем я инвестировал до сих пор.

Здесь вы можете найти реализацию Mono T4:

https://github.com/mono/monodevelop/tree/master/main/src/addins/TextTemplating

Я документировал некоторые из проблем, с которыми я столкнулся, пытаясь запустить T4-шаблоны из .NET-кода здесь:

Параметры для запуска шаблонов T4 из .NET-кода

Ответ 6

Одна ошибка, которую я сделал, - это добавить файл "Текстовый шаблон". Чтобы сгенерировать текст в время выполнения, выберите вместо него "Preprocessed Text Template". Если вы изначально выбрали "Текстовый шаблон", это простое изменение, чтобы настроить пользовательский инструмент на "TextTemplatingFilePreprocessor" в свойствах файла в VS.