Pull to refresh

.NET Core 2.1 dependency injection framework

30 мая вышла версия фремворка .NET Core 2.1

Я создал build — .NET Core 2.1 фреймворк, направленный на реализацию внедрения зависимостей в .NET Core.

Что такое внедрение зависимостей? Это один из вариантов рефакторинга существующего кода, когда объекты, напрямую связанные друг с другом, то есть упомянутые в качестве параметра конструктора, в качестве публичных свойств и внутренних переменных, внедряют вместо себя в зависимые классы независимые (то есть не подверженные изменению) и внешние по отношению к этому конкретному классу объекты, В C# это может быть как тип System.Object, так и любой тип, представляющий собой реализацию интерфейса. В случае с интерфейсом, интерфейс эффектвно предоставляет себя как API для реализующего этот класс интерфейса и тем самым разрешает независимую компиляцию и изменение в прошлом зависимых объектов путем внедрения непрямой зависимости от интрефейса объекта, а не собственно объекта.

Реализация build использует вариант внедрения зависимостей через конструктор и атрибутивное метапрограммирование. Мне показалость, что идея интересна в первую очередь тем, что по своей природе, объекты, конструируемые программно, имеют следующую особенность:
Все зависимости обекта должны быть удовлетворены до начала времени жизни обьекта
В случае с внедрением зависмостей через свойства, когда собственно объект уже создан, метод конструктора уже вызван и объект для которого удовлетворяются зависмости конструкторм обьекта, уже существует в памяти. Я называю это состоянием ошибки просто потому что в этом состоянии, совершенно допустимо получить доступ к объекту, сделать вызов к этому объекту и выполнить какой-либо из методов и получить какие-либо свойства.

В случае, если вы хотите использовать внедрение через свойства, вот несколько вещей, на которые стоит обратить внимание: нет никакого способа которым вы можете предотвратить вычисление свойств (незавершенного объекта, объекта в состоянии ошибки), такого, что без внедрения дополнительных зависимостей от конструктора объекта или признака внутреннего состояния объекта, объект посчитает что он создан правильно, и все его зависимости удовлетворены, в противном случае вам придется предоставить коммуникационныый протокол между конструируемым объектом и конструирующим объекто (builder), который может быть использован нижераспологающимся конструируемым объектом с целью просто определения степени завершенности процесс собственного конструирования для начала вычислений и работы. Этот случай мне напоминает дилог хирурга и пациента во время проведения операции без анестезии, это боль.

Итак, я решил использовать внедрение зависимостей через конструктор просто для уверенности что никто не будет задавать мне вопросы во время операции, будучи защищенным на уровне компилятора.

Представьте себе, у вас есть объекты A, B, C, и D, которые зависят друг от друга. A зависит от себя самого, B имеет зависимость в A, C имеет зависимость в B, D имеет зависимость в C и A так же имеет зависимость в D. В нормальных условиях, вы сможете скомпилировать этот код, но вы никогда не сможете создать экземпляры этих классов до тех пор, пока вы не поредложете альтернативный способ создания объектов, эффективно разрушающий взаимную зависимость этих классов друг от друга. Но это еще не вся история. Вам придется удалить все циклические ссылки в коде для получения возможности создания экземпляров указанных объектов. Например, для A, если зависимости реализованы одним конструктором, скажем

A(A other, B b), то

вам придется обеспечить:

  1. конструктор по-умолчанию A(), чистый копирующий конструктор A(A other) и A(B b), или
  2. конструктор по-умолчанию A(), и устранить зависимость от A в D(A a)

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

D([A()]A a),

вы определенно избежите ошибку переполнения стека при разрешении зависимостей оъектов, и будете жить долго и счастливо с копилятором .NET по вашему выбору.

Счастливого программирования!

С уважением, Артур Мустафин, программист.

В случае если вы не заметили по картинке ниже, все стрелки должны быть реверсированы для того чтобы отразить пример выше, но это НОРМ для моей 4-летнего малыша, подготовивишего картинку к этом посту. Так-же, некторые условные обозначения на русском, не обязательно коррелируют с буквами A,B,C,D, соответственно. Все использованные изображения посте являются копирайтом и защищены законом об авторских правах и были использованы с устного соглаия на публичное размещение от Елизаветы Мустафиной, в возрасте 4.

image
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.