Опять кодогенерация, шаблонизаторы vs AST
![топ 100 блогов](/media/images/default.jpg)
И поначалу это гораздо понятнее, чем кодогенератор с использованием AST целевого языка и претти-принтингом оного AST в исходники.
Но есть одно НО.
Результат без подсветки синтаксиса и автоформатирования к поддержке практически непригоден. Исходник представляет собой смесь C# кода, который выполняется и C# кода который генерируется, с разделителями вида <#,<#=,<#+ и #>. Без заточенного под это дело редактора после определенного уровня сложности кодогенератора в этом понять ничего невозможно.
Например, я, упившись крепким чаем, в припадке безумия таки реализовал свою старую идею - генерацию из простой модели иммутабельных сущностей и методов сохранения и загрузки оных сущностей в простой XML, где полям-значениям соответствуют атрибуты, полям-объектам - элементы, полям-спискам(List<>) - элементы с вложенными списками. Т.е. вариант XML, в котором это дело наиболее читабельно глазами. Если не боитесь пауков - можете глянуть на этот мрак.
По мере расширения этого кодогенератора (простые сущности-записи -> сущности с полями-списками -> поддержка enum -> поддержка полей-вложенных объектов -> поддержка memo-полей (строки в которых длинный текст с переносами)) это все понемногу превратилось в жопный ад. 10 кб текста, 300 строк, в которых даже я с трудом ориентируюсь уже.
Использовать это очень просто, расширять дальше - уже сложно.
Кроме того, во всей этой кодогенерации очень бесит необходимость постоянно расширять систему типов. Т.к. один и тот же string в целевой проге - это может быть и коротенькое имя, и текст SQL запроса и RTF-документ. А при показе поля с датой пользователю может быть необходимо использовать culture-invariant формат (например я для служебных данных и для себя пользуюсь везде только им, чтобы не вспоминать "на какой локали я сижу") а может и формат из текущей локали.
В общем, если делать классическими дотнетовскими средствами, как положено, то на каждое поле или проперть в POCO-сущности навешивается еще 5-10 атрибутов, и по всему коду расползается анализ этих атрибутов, т.е. фактически мало того, что мы расширяем систему типов дополнительными описаниями, так еще и всю их обработку делаем в рунтайме, как с какой-то динамической типизацией.
PS: Во, вспомнил еще идею, которая мне насчет T4 в голову пришла.
Частенько в C# не хватает ADT, но их можно сымитировать, сделав базовый класс и унаследовав от него все варианты ADT с нужными полями. Чтобы сделать pattern matching поверх этого, нужно написать в базовом классе метод, в который передается в качестве параметров по одному делегату на каждый вариант ADT и он анализирует текущий тип объекта, вызывая соответствующий делегат, подставляя поля варианта в качестве параметров делегату.
Руками такое писать очевидно влом. Но можно сделать на T4 мелкий шаблончик, который из описания ADT в привычном виде сгенерит все классы, конструктора, прототипы делегатов и метод для pattern matching.
|
</> |