Re: Introducing C# Source Generators
От: Goldy  
Дата: 04.06.20 06:37
Оценка: 32 (3)
Всем привет!

Хочу поделиться своим опытом работы с генераторами.
Несколько лет назад игрался с аналогичной библиотекой для генерации кода
CodeGenerator.Roslyn

Ради эксперимента потратил пару дней чтобы попробовать сделать не только генерацию а возможность модификации исходного кода.
Вот что получилось в итоге.
Пример:

    [TryCatchOrdered(ExecutionOrder = 1)]
    [DuplicateWithSuffixByNameOrdered("t", ExecutionOrder = 2)]    
    [RemoveOrdered(ExecutionOrder = 3)]
    public partial class Foo
    {
        [DuplicateWithSuffixByNameOrdered("t", ExecutionOrder = 1)]
        public object `Prop1;

        [DuplicateWithSuffixByNameOrdered("k", ExecutionOrder = 1)]
        public int? Prop2;

        public void Test()
        {
            var aa = 1;
            var dd = 3;
            var bb = 0;
            var cc = aa / bb;
        }
    }



После трансформации код заменяется на:
    [TryCatchOrdered(ExecutionOrder = 1)]
    [DuplicateWithSuffixByNameOrdered("t", ExecutionOrder = 2)]
    [RemoveOrdered(ExecutionOrder = 3)]
    public partial class Foot
    {
        [DuplicateWithSuffixByNameOrdered("t", ExecutionOrder = 1)]
        public object Prop1;
        [DuplicateWithSuffixByNameOrdered("t", ExecutionOrder = 1)]
        public object Prop1t;
        [DuplicateWithSuffixByNameOrdered("k", ExecutionOrder = 1)]
        public int? Prop2;
        [DuplicateWithSuffixByNameOrdered("k", ExecutionOrder = 1)]
        public int? Prop2k;
        public void Test()
        {
            try
            {
                var aa = 1;
                var dd = 3;
                var bb = 0;
                var cc = aa / bb;
            }
            catch (Exception ex)
            {
            }
        }
    }


Что происходит в результате трансформации:
1) Вначале применяются все атрибуты для нижнего уровня свойства методы и т.д.
В данном случае атрибут DuplicateWithSuffixByNameOrdered служит для дублирования объявления свойства или класса с другим именем — к имени добавляется суффикс
2) Потом применяются все атрибуты для классов:
Атрибут TryCatchOrdered — модифицирует все методы класса оборачивая содержимое в try {} catch {} (чисто для примера)
Атрибут DuplicateWithSuffixByNameOrdered — для дублирования класса с другим именем
Атрибут RemoveOrdered — для удаления исходного класса с именем Foo (если его убрать то будет 2 класса Foo и Foot)

В принципе метод рабочий, чтобы заставить работать пришлось сильно пободаться с иммутабельностью в Roslyn
Если развивать дальше то можно сделать поддержку AOP, макросов и других вещей.
Единственный непонятный момент что делать с отладкой сгенерированного кода.

P.S. На исходном форуме мое сообщение особого интереса не вызвало и проект я забросил.

Кому интересно можно поиграться с проектом в репе:
https://github.com/GoldyD/CodeGeneration.Roslyn
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.