В первую очередь нам нужен движек текстовых шаблонов.
По сути он будет похож на сегодняшнюю $-строку, но все же будет отличаться некоторыми расширенными возможностями:
1. Главное отличие заключается в том, что шаблон должен жить не сам по себе, а в составе и при непосредственном взаимодействии с другими шаблонами. Такие шаблоны объединяются в группу шаблонов.
2. Все шаблоны группы должны использовать для генерации текста единый для группы StringBuilder. Это обеспечит высокую скорость генерации текста.
3. Шаблоны должны позволять рекурсивное применение.
5. У шаблона должно быть описание входных параметров. Они могут исползовать в $ и ..$ конструкциях.
Группы шаблонов я вижу себе в виде класса (возможно помеченного неким атрибутом). Например:
[StringTemplateGroup]
class MyStringTemplateGroupe
{
...
}
Каждый шаблон можно описывать как некую псевдо-функцию тело которой не код, а строка с $-включениями. Вот пример группы шаблонов генерирующих код создания и удаления индексов.
[StringTemplateGroup]
class MethodGenerator
{
// Описывает генерацию индекса.
public virtual CreateIndex(index : Index, table : Table, isClustered : bool,
isUnique : bool) : string StringTemplate
<[
CREATE $(Unique(index.IsUnique)) $(Clustered(index.IsClustered)) INDEX $(Quot(index.Name)) ON $(Quot(table))
(
..$(index.EntryColumns; "\n"; entry => $(entry.Column) $(Direction(entry.IsAscending)))
)
]>
// Генерирует выражение удаления индекса.
// name - имя индекса подлежащего удалению.
// table - имя таблицы индекс которой требуется удалить.
public virtual DropIndex(name : string, table : string) : string StringTemplate <[
DROP INDEX $Quot(name)$ ON $Quot(table)$
]>
// Добавляет к имени символы цитирования. Это позволяет именам содержать
// пробельные символы и пересекаться с ключевыми словами
protected virtual Quot(name : string) StringTemplate <[
[$name]
]>
// Выводит сточку "UNIQUE" если isUnique равен true.
// Это просто фукнция! Ее тело не является шаблоном.
protected virtual Unique(isUnique : bool) : string
{
if (isUnique) " UNIQUE" else ""
}
...
// Выводит сточку ASC" если isAscending равен true или "DESC" в обратом случае.
protected virtual Direction(isAscending : bool) : string
{
if (isAscending) "ASC" else "DESC"
}
...
}
Общая идея такова. Данный код обрабатывается макросами и преобразуется в эффективный код генерации строк (с использованием StringBuilder-а).
Для каждого шаблона в группе создается две функции одна срытая имеющий прототим:
protected ИмяШаблона(список_параметров_шаблона) : void;
А другая имеющая прототип аналогичный описанному в группе. В случае рекурсивного вызова шаблонов вызывается скрытая функция. Это исключает лишние преобразования в строку, так как скрытая версия функции выводит генерируемый текст в StringBuilder.
Публичную функцию может вызвать пользователь. При этом внутренний StringBuilder сбрасывается, производится вызов скрытой версии фукнции, а затем содержимое внутреннего StringBuilder-а преобразуется в строку и возвращается наружу как возвращаемое значение функции.
... << RSDN@Home 1.2.0 alpha rev. 637>>