Skip to content
This repository was archived by the owner on Feb 13, 2023. It is now read-only.

psynomorph/Injectikus

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Injectikus - ещё один контейнер внедрения зависимостей

Базовые примеры использования

IContainer container = new BaseContainer();

// Регистрация класса, как реализации интерфейса
container.Bind<I>().To<ClassImplementsI>();

// Есть поддержка фабричных делегатов
container.Bind<I>().ToMethod(container => new ClassImplementsI(container.Get<ClassDependencyType>()));

// И произвольных объектов - поставщиков
class ClassClassImplementsIProvider : ObjectProvider<ClassImplementsI>
{
    public ClassImplementsI Create(IContainer container)
    {
        return new ClassImplementsI(container.Get<ClassDependencyType>());
    }
}
container.Bind<I>().ToProvider(new ClassClassImplementsIProvider());

// Есть возможность использовать объекты-одиночки (Singleton)
container.Bind<I>().Singleton().To<ClassImplementsI>();
container.Bind<I>().Singleton().ToMethod(container => new ClassImplementsI(container.Get<ClassDependencyType>()));
container.Bind<I>().Singleton().ToProvider(new ClassClassImplementsIProvider());

// Также можно указывать конкретные объкеты
// так
container.Bind<I>().Singleton().ToObject(new ClassClassImplementsI());
// или так
container.Bind<I>().Singleton(new ClassClassImplementsI());

// Для указания типа, как реализации самого себя можно использовать метод расширения IContainer.ToThemselves()
container.Bind<ClassImplementsI>().ToThemselves();

// Для получения экземпляра можно использовать методы Get и GetAll
var object = container.Get<I>();
if (container.GetAll<I>(var out obj)) {
    ...
}

// Также можно для одного базового типа зарегистрировать несколько реализаций и получить их массив
container.Bind<I>().To<FirstClassImplementsI>();
container.Bind<I>().To<SecondClassImplementsI>();

I[] objects = container.GetAll<I>();

// С помощью метода CreateInstance<T> можно создать экземпляр класса T, не зарегистрированного в контейнере, с внедрением в него зависимостей из контейнера
var object = container.CreateInstance<SomeClass>();

// Можно проверить, способен ли контейнер разрешить зависимость
if (container.CanResolve<I>())
{
    ...
}

Также у всех вышепреведенных методов присутствуют необобщенные версии, для возможность определять типы в рантайме
container.Bind(typeof(I)).To(typeof());
object @object = container.Get(typeof(I))

Стратегии создания экземпляра класса и внедрения зависимостей

Контейнер поддерживает несколько стратегий создания экземпляра класса и внедрения зависимостей.

  • Внедрение в отмеченный атрибутом конструктор класса

    class Car
    {
        [InjectHere]
        public Car(IEngine engine)
        {
            ...
        }
    }
  • Внедрение зависимостей в помеченные атрибубутом публичные свойства и параметры методов-сеттеров

    class Car
    {
        [InjectHere]
        public IEngine Engine { get; set;}
    
        [InjectHere]
        public void SetTransmission(ITransmission transmission)
        {
            ...
        }
    }
  • Внедрение зависимости через аргументы одно определенного метода - инициализатора

    class Car
    {
      [InjectHere]
      public void Init(IEngine engine, ITransmission transmission)
      {
          ...
      }
    }
  • Внедрение зависимостей через аргументы конструктора с наибольшим количеством разрешимых контейнером аргументов.

    class Car
    {
        // В зависимости от того, 
        // может ли контейнер в момент создания экземпляра 
        // разрешить типы IEngine и ITransmission, 
        // будет вызван один из трёх конструкторов объекта
    
        public void Car(IEngine engine, ITransmission transmission)
        {
            ...
        }
    
        public Car(ITranmission transmission)
        {
            ...
        }
    
        public Car(IEngine engine)
        {
            ...
        }
    }
  • Использование конструктора по умолчанию без внедрения зависимостей

    class DodgeCharger
    {
        public DodgeCharger()
        {
            engine = new V8Engine();
            transmission = new SixSpeedAutomaticTransmission();
        }
    }

Указать конкретный метод инициализации для класса, можно с помощью атрибута InjectionMethod

[InjectionMethod(DependencyInjectionMethod.ConstructorParametersInjection)]
class Car
{
    [InjectHere]
    public Car(IEngine engine)
    {
        ...
    }
}

Если атрибут InjectionMethod не указан, то метод инициализации будет выбран автоматически, в зависимости от того, использованы ли атрибуты библиотеки на каких-либо членах класса и какие конструкторы доступны.

Так же возможно внедрение массива объектов необходимого типа (аналог GetAll). Для этого необходимо использовать аттрибут InjectArray

class Garage
{
    [InjectHere][InjectArray]
    public ICar Cars { get; set; }
}

// Или

class Garage
{
    [InjectHere]
    public Garage([InjectArray] ICar[] cars)
    {
        ...
    }
}

Конструкторы, методы инициализации и сеттеры могут иметь опциональные параметры. В таком случае при наличии зависимости в контейнере в них будет передана зависимость, в противном случае - значение по-умолчанию.

class Car
{
    public IEngine Engine { get; }
    public ITransmission Transmission { get; }

    [InjectHere]
    public Car(IEngine engine, ITransmission transmission = null)
    {
        Engine = engine;
        Transmission = transmission ?? new MechanicFiveSpeed();
    }
}

Releases

No releases published

Packages

No packages published

Languages