Подтвердить что ты не робот

Внедрение зависимостей с использованием ткачества во время компиляции?

Я просто пытался узнать о PostSharp и, честно говоря, думаю, что это потрясающе.

Но одно из того, что мне трудно понять, как не может быть реализована чистая инъекция зависимостей (не сервисный локатор) в аспектах PostSharp, возможно, в моем понимании в результате времени компиляции.

Приведенный из фона PHP, Symfony имеет JMSAopBundle, который до сих пор позволяет ему вводить зависимость Interceptor.

Есть ли у .NET какие-то библиотеки с одинаковыми возможностями?

Или я что-то пропускаю с PostSharp?

4b9b3361

Ответ 1

Я не думаю, что вы ничего здесь упускаете, и ограничение действительно является результатом использования ткачества времени компиляции.

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

  • интерфейс ICommandHandler<TCommand> для сервисов, которые реализуют определенный вариант использования;
  • интерфейс IQueryHandler<TQuery, TResult> для служб, которые выполняют запрос;
  • интерфейс IRepository<TEntity> как абстракция над репозиториями;
  • интерфейс IValidator<TCommand> для компонентов, которые выполняют проверку сообщений;
  • И так далее, и так далее.

Это позволяет мне создать единый универсальный декоратор для такой группы артефактов (например, TransactionCommandHandlerDecorator<TCommand> который позволяет запускать каждый TransactionCommandHandlerDecorator<TCommand> использования в своей собственной транзакции). Использование декораторов имеет много преимуществ, таких как:

  • Эти универсальные декораторы полностью независимы от инструментов, поскольку нет ссылки на инструмент для создания кода или библиотеку перехвата. Аспекты PostSharp полностью зависят от PostSharp, а перехватчики всегда зависят от инфраструктуры перехвата, такой как Castle.DynamicProxy.
  • Поскольку декоратор является просто нормальным компонентом, зависимости могут быть введены в конструктор, и они могут играть нормальную роль, когда вы составляете свои графы объектов с помощью Dependency Injection.
  • Код декоратора очень чистый, поскольку отсутствует зависимость от какого-либо стороннего инструмента.
  • Поскольку они не зависят от инструментов и допускают внедрение зависимостей, декораторы могут быть легко протестированы модульно, без необходимости возвращаться к специальным трюкам.
  • Прикладной код, который требует применения сквозных задач, также может быть легко протестирован в изоляции, поскольку декораторы не включаются во время компиляции. Когда декораторы включаются во время компиляции, вы всегда вынуждены выполнять интеграционный стиль тестирования кода своего приложения или должны возвращаться к специальным приемам сборки, чтобы предотвратить их применение в проекте модульного тестирования.
  • Декораторы могут быть применены динамически и условно во время выполнения, так как не происходит переплетения кода времени компиляции.
  • Производительность идентична (или даже выше), чем при переплетении кода, потому что во время конструирования объекта не происходит отражения.
  • Там нет необходимости отмечать ваши компоненты с атрибутами, чтобы отметить, что некоторые аспекты должны быть применены. Это освобождает код вашего приложения от каких-либо знаний о таких сквозных проблемах и значительно упрощает его замену.

Много было написано об этом виде разработки приложений; Вот несколько статей, которые я написал сам:

ОБНОВИТЬ

Декораторы великолепны, но в AOP мне нравится концепция советов и точек соединения. Есть ли способ симулировать такую же возможность с декоратором? Я мог только думать об отражении прямо сейчас.

Точка соединения - это "четко определенное место в классе, к которому нужно присоединиться". Когда вы применяете AOP с использованием декораторов, вы будете "ограничены" для объединения точек, находящихся на границах метода. Однако, если вы придерживаетесь SRP, OCP и ISP, у вас будут очень тонкие интерфейсы (обычно одним способом). Делая это, вы заметите, что вряд ли когда-либо есть причина для того, чтобы иметь точку соединения в любом другом месте в ваших классах.

Совет - это "проблема, которая потенциально изменит входные и/или выходные данные целевого метода". При работе с декораторами и дизайном на основе сообщений (то, что я здесь рекламирую), вашему Совету необходимо изменить сообщение (или заменить полное сообщение измененными значениями) или изменить выходное значение. Вещи не сильно отличаются от ткачества кода - если вы применяете Совет, между всем кодом, к которому применяется Совет, должно быть что-то общее.