алгоритми кодогенераціі

Кодогенерацію при програмуванні з використанням платформи Microsoft.NET

Вступ
Кодогенерацію «в лоб»
Кодогенерацію з використанням шаблонів
Кодогенерацію з використанням шаблонів XSLT
Кодогенерацію з використанням ASP.NET
Кодогенерацію на декількох мовах
Кодогенерацію на декількох мовах з використанням шаблонів CodeDOM
Кодогенерацію під час виконання

алгоритми кодогенераціі

Не секрет, що іноді при програмуванні якогось завдання доводиться виконувати великий обсяг нудною рутинної роботи, і позбутися від неї штатними засобами ООП не вдається. Крім того, ситуація ускладнюється і відсутністю в мовах .NET generic типів.

В .NET Framework кодогенерацію також застосовується досить часто. Наприклад, за допомогою кодогенератор на основі xsd-файлів зі схемою даних створюються типізовані набори даних (typed datasets), за допомогою кодогенератор створюються проксі-класи для веб-сервісів. Під час виконання генерують код для підвищення продуктивності класи System.Xml.Serialization.XmlSerializer, System.Text.RegularExpressions.Regex, System.Web.UI.PageParser.

Кодогенерацію «в лоб»

Першим, що зазвичай приходить на розум - це генерувати код на будь-якій мові програмування «безпосередньо». Припустимо, необхідно по якомусь опису набору властивостей згенерувати клас. Задамо опис у вигляді xml-файлу:

Це опис буде знаходитися в одній з збірок проекту в якості ресурсу.

Для представлення структури класів всередині програми створимо набір класів, з якими буде працювати алгоритм кодогенераціі. Щоб вручну не створювати об'єктне уявлення з xml, скористаємося класом XmlSerializer.

Клас XmlSerializer є серіалізатор об'єктів в xml. При цьому, на відміну від формату, що видається SoapFormatter, в даному випадку формат xml піддається більш ретельному контролю. Зокрема, у наведеному нижче прикладі атрибутом XmlRoot задається назва кореневого тега, атрибутом XmlAttribute задається збереження якості в значенні атрибута з вказаним ім'ям, атрибутами XmlArray і XmlArrayItem спосіб представлення масивів і списків.

І, хоча «сенс» функції не змінився, вона стала коротше, а, головне, помітно зрозуміліше при читанні. У тих випадках, коли статичного тексту багато, наприклад, в разі типізованих колекцій, подібний підхід значно зручніше першого. Однак в нашому прикладі в кодогенератор виявилося досить багато ручного коду. Основна причина цього полягає в необхідності здійснювати ітерації вручну. Непогано було б цю ітерацію вказувати прямо в шаблоні. Можна, звичайно, написати відповідний макропроцесор, але ми підемо іншим шляхом. Скористаємося готовими рішеннями.

Кодогенерацію з використанням шаблонів XSLT

Одним з готових рішень для створення шаблонів є частина стандарту W3C XSL - XSL Transformation, скорочено XSLT. Ця технологія призначена для перетворення xml-файлів в інше уявлення і володіє дуже великою гнучкістю.

XSLT є мова програмування, оптимізований для цілей завдання правил перетворення. XSLT-файл складається з набору правил, які охоплюють тегами template. На відміну від класичних мов, XSLT описує перетворення не як алгоритм дій, а як набір правил, що застосовуються до вузлів вхідного xml. Кожне правило містить логічну функцію, предикат, обчислюючи яку можна визначити, чи підходить воно для поточного вузла. У разі XSLT для опису подібних функцій застосовується спеціальна мова, XPath. Якщо предикат повертає true, виконується вміст правила, яке складається з статичного тексту і набору тегів, що нагадують синтаксичні конструкції логічних мов - друк значення, цикл, умова і т. Д. Крім того, тегом apply-templates задається продовження обробки для вкладених вузлів. Обробка файлу ведеться, починаючи з кореневого вузла.

Повний опис XSLT ви можете знайти на сайті World Wide Web Consortium, www.w3c.org

Все, кодогенератор готовий.

Кодогенерацію на декількох мовах

Платформа Microsoft.NET підтримує програмування на декількох мовах. Якщо важливо не просто отримати кінцевий результат, але отримувати вихідний код на разниз мовах програмування, також вельми бажана наявність підтримки декількох мов. Однак наведені раніше приклади кодогенератор для додавання підтримки мови потребують або в повному переписуванні, або, по крайней мере, в повній переробці шаблонів. Для вирішення цієї проблеми Microsoft пропонує технологію CodeDOM.

Процес генерації коду з використанням цієї технології виглядає наступним чином. Спочатку вибудовується дерево узагальнених синтаксичних конструкцій мови, яке потім CodeDOM-провайдером конкретного мови перетвориться у вихідний текст.

Спробуємо реалізувати кодогенератор з самого першого прикладу з використанням CodeDOM.

Кодогенератор для Visual Basic.NET видасть такий код:

Однак легко помітити, що у щойно наведеного прикладу є той же самий недолік, з яким ми боролися протягом всієї статті, а саме генерація статичних (незмінних) частин коду. На жаль, ті підходи, які ми застосовували для боротьби з цим недоліком, в разі багатомовними конфігурації вже не підходять.

Кодогенерацію на декількох мовах з використанням шаблонів CodeDOM

Зрозуміло, що в цьому випадку шаблон для генерації повинен бути представлений у вигляді CodeDOM-дерева. Питання полягає тільки в тому, як його отримати. Можна, звичайно, розбирати вихідний код на тому ж C #, однак парсинг таких мов - справа непроста, та й не всі конструкції С # можна виразити в CodeDOM.

Тому в якості мови опису CodeDOM-шаблонів використовуємо мову з готовим парсером - XML.

На жаль, в рамках цієї статті неможливо реалізувати парсер XML-опису CodeDOM з урахуванням всіх його можливостей, тому реалізуємо тільки ту частину, яка необхідна для реалізації прикладу. Для реалізації скористаємося тим же способом, яким ми завантажували вихідні дані, тобто XmlSerializer. Для класів, що представляють елементи шаблону визначимо абстрактний базовий клас:

Оголосимо в ньому віртуальний метод, який буде повертати відповідний елементу шаблону елемент CodeDom. Повний вихідний код класів для завантаження з xml знаходиться на доданому до журналу компакт-диску.

Тепер реалізуємо шаблон. Оскільки і вхідні, і вихідні дані виражені у вигляді XML, то скористаємося XSLT-перетворенням.

Використовуючи подібну техніку, можна реалізовувати дуже ефективні алгоритми, оптимізовані під конкретні дані. Продуктивність при грамотній реалізації кодогенераціі порівнянна з повністю ручної реалізацією алгоритмів для конкретних даних. Наприклад, швидкість десеріалізациі XmlSerializer деревовидної структури практично така ж, як ручне читання з XmlReader, і значно (в 2-3 рази) вище швидкості SoapFormatter, що використовує універсальні алгоритми і механізм відображення (reflection). Швидкість роботи ASP.NET, що використовує кодогенерацію на складних алгоритмах, відчутно вище швидкості ASP, що використовує інтерпретацію.

Однак є у наведеного прикладу і один недолік, в деяких випадках істотний. Компіляція з вихідних кодів - це дуже повільний процес. Помітити це можна, наприклад, за значної затримки завантаження aspx-сторінки при її зміні. Але і в цьому випадку є вихід - .NET Framework дозволяє створювати збірки відразу в IL-кодах.

При генерації збірки вивантажити її з пам'яті можна тільки при вивантаженні всього домену. Тому при частій перегенерации збірки краще створювати в окремому домені і вивантажувати цей домен, як тільки потреба в ньому зникне.

Кодогенерацію відразу в IL-код

Для створення збірок «на льоту» механізм відображень надає набір можливостей, виділених в простір імен System.Reflection.Emit. Спробуємо згенерувати класи відразу в збірку, минаючи генерацію вихідних кодів і компіляцію.

висновок

Наведені вище приклади показують, як за допомогою кодогенераціі будувати гнучкі і максимально адаптовані системи, не обмежені можливостями використовуваних мов.

На жаль, у кодогенераціі є один серйозний недолік - результат кодогенераціі не можна змінювати. Однак останнім часом на ринку з'являються системи, здатні не тільки генерувати код зі структури даних, а й перетворювати код назад у вихідні дані. Досягається це шляхом парсинга згенерованого коду і порівнювання структур вихідного і отриманого дерев з виявленням внесених вручну змін, щоб потім, при наступної генерації, врахувати ці зміни. Швидше за все, за подібними системами майбутнє.

Схожі статті