Как стать автором
Обновить

Комментарии 14

Какой смысл добавлять original/processed как часть синтаксиса языка, если это свойство не отдельного класса, а целого файла? К тому же для IDE гораздо проще достать обработанную версию файла через интеграцию с Roslyn, что технически возможно уже сейчас, чем парсить двойной набор файлов и искать попарные взаимные соответствия между ними...

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

Также как и сейчас вы можете иметь несколько partial определений одного и того же класса в одном файле, так и с original/processed, вы можете иметь оба определения в одном и том же файле, спецификация языка не смотрит на детали реализации компилятором.

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

Статья и так получилась слишком длинная и/или занудная, если бы начал перегружать деталями то еще хуже получилось бы.

Похоже не только лишь все долетели до её конца. Обычно здесь желающих попинать чужие идеи сильно больше. Я думал что по крайней мере пример с DependencyInjection вызовет отклик, так как апологетов использования DI на пару порядков больше чем AOP. Для DI кстати тоже есь предложение включить в язык ключевое слово — inject/inject one of, которое решает одну из его основных проблем (по крайней мере в моём случае), отсутсвие видимости ожиданий. Т.е. сейчас мы не можем явно потребовать провести инекцию, а только надеятся что она будет проведена. И не можем упасть на момент компиляции, если у нас нету правильных кандидатов на это.

А как вообще могут original- и processed-версии одного и того же класса существовать в одном и том же файле? Это что получается, после каждой компиляции файл перезаписывается? Абсурд же, хотя бы с точки зрения систем контроля версий исходников.


Для DI кстати тоже есь предложение включить в язык ключевое слово — inject/inject one of, которое решает одну из его основных проблем (по крайней мере в моём случае), отсутсвие видимости ожиданий. Т.е. сейчас мы не можем явно потребовать провести инекцию, а только надеятся что она будет проведена.

Да ладно? Достаточно добавить параметр в конструктор — и без передачи этого параметра объект просто не сможет быть создан.

А как вообще могут original- и processed-версии одного и того же класса существовать в одном и том же файле?
Почему нет, с точки зрения практического применения два partial определения одного и того же класса в одном файле тоже не несут большой пользы.
Это что получается, после каждой компиляции файл перезаписывается?
С точки зрения компилятора, процесс трансформации это чёрный ящик. Компилятор делает первый проход, запусает процесс трансформации (это может быть например пустой cmd файл) после успешного окончания процесса, запускает второй проход. Что там происходит и какие файлы генерируется его не волнуют, главное чтобы на втором проходе выполнились условия для успешного продолжения сборки.
Достаточно добавить параметр в конструктор — и без передачи этого параметра объект просто не сможет быть создан.
Может быть мы с вами разными DI framework-ами пользовались, но у меня всё себе вполне создаётся и цепные инекции осуществляются.

Я говорил про то, что сейчас когда я пишу (или что главнее читаю) код, для меня строка
private IDataService _service { get; }
Ничего не говорит о том что это специальный случай. Т.е. я должен в подкорке держать факт что у нас есть DI и что может быть (может быть) это свойство будет инициированно этим DI. Тогда как
private IDataService _service { get; } = inject;
Явно указывает на это и требует чтобы произошла инекция. И при отладке будет явно виден код инициализации. И не на момент отладки, а даже на момент просто просмотра кода .processed.cs

Я думал в моём примере для шаблона DependencyInjection.t4 это было видно.
Там конечно хак с определением static dynamic property с именем inject, но даже этот вариант гораздо более выразителен чем вариант с его отсутствием. Плюс инекция для локальных переменных, когда отсутсвияе явной инициализации послужит ошибкой компиляции.
Может быть мы с вами разными DI framework-ами пользовались, но у меня всё себе вполне создаётся и цепные инекции осуществляются.

Так у меня тоже. Почему вы считаете это проблемой?


Ничего не говорит о том что это специальный случай. Т.е. я должен в подкорке держать факт что у нас есть DI и что может быть (может быть) это свойство будет инициированно этим DI.

А почему вам важен тот факт, что это свойство инициализировано именно через DI, а не как-то ещё?


И при отладке будет явно виден код инициализации. И не на момент отладки, а даже на момент просто просмотра кода .processed.cs

Я этот код даже в оригинальном файле вижу. Смотрите:


public SomeClass(IDataService service) {
    this._service = service; // тот самый код инициализации!
}
Так у меня тоже. Почему вы считаете это проблемой?
Я не cчитаю это проблемой. Проблемой является то, как это используется в реальных проектах. И когда я прихожу в проект, где используется инекция и вижу
private IDataService _service { get; }
и где-то в недрах файла конфигурации инекций существует правило, что давайте при создании класса в котором есть свойство IDataService, инициализировать это свойство новым экземпляром DataService/MockDataService.

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

Когда в классе пятьдесят свойств и десять из них инициализируется инекцией, а сорок явно дальше по коду, то читая этот код, я вынужден каждый раз бегать вниз (или вверх) по цепочке. И не обнаружив явную инициализацию, бежать в мир инекций и пытаться заресолвить что случится там (и вообще случится ли).
А почему вам важен тот факт, что это свойство инициализировано именно через DI, а не как-то ещё?
Мне не важен факт того что «что это свойство инициализировано именно через DI», мне важно то, что оно может быть НЕ иниализированно через DI, со всеми вытекающими плясками. В реальной разработке, я лично сотню раз наступал на эти грабли и продирался через отладчик в надежде выявить где и что косячнуло.
Я этот код даже в оригинальном файле вижу.
А я вижу другой код и можно конечно топить за то чтобы следовать стилю, как оно должно быть правильно, а можно принять тот факт, что DI это состоявшаяся практика и поддержать её на уровне языка.
А я вижу другой код и можно конечно топить за то чтобы следовать стилю, как оно должно быть правильно, а можно принять тот факт, что DI это состоявшаяся практика и поддержать её на уровне языка.

Ну и какой ещё код там может быть? Вы что, вообще без инициализации оставляете свойства, а потом устанавливаете их через отражение?


Просто не делайте так, и всё будет в порядке.

Просто не делайте так, и всё будет в порядке.
Я про это же и говорю. Но когда приходишь на пятнадцателетний проект и до этого там поработало шесть разных команд разработчиков, «Просто не делайте так» не работает, потому что всё уже сделано до нас. И вас взяли на решение вполне конкретных задач, а не на переписывание того что работает.

Ну так в пятнадцатилетнем проекте и ни аспектов вы никаких не увидите, ни новых ключевых слов, ни даже компиляции через Roslyn...

Ребят, посмотрите на язык Немерле — он на порядок круче всей этой АОПушной фигни и позволяет намного больше.
Я думаю что вы сами прекрасно понимаете причины по которым ни один здравомыслящий человек не потянет в рабочий проект новый язык, который не знает практически никто.

Моя статья описывает решение реальной проблемы, в том числе для уже существующих проектов, существующей кодовой базы, без фундаментальных изменений.

Если же добавить новый (не в смысле даты его создания, а в смысле раннее не используемый в проекте), эксперементальный язык в проект, то вместо одной проблемы, у вас их станет две.
C# Source Generators () не помогут Вам?
В статье про них написано и написано почему нет (они позволяют добавлять новый код, но не модифицировать старый).
The key difference is that Source Generators don’t allow you _rewrite_ user code

В случае AOP мы добавляем логику аспектов в существующий код. Наш инструмент через исходный код, многие другие через «вплетение» байткода.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации