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

Как передать параметр конструктору с помощью Simple Injector?

Простой инжектор позволяет передавать параметры конструктору при его разрешении? Я хотел бы знать, делают ли обе эти структуры то, что делают Unity ResolverOverride или DependencyOverride.

4b9b3361

Ответ 1

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

Пусть настроен простой тестовый класс:

public interface IFoo
{

}

public class Foo : IFoo
{
    public Foo(string value)
    {

    }
}

Класс Foo принимает строковый аргумент, который мы хотели бы предоставить при разрешении службы IFoo.

var container = new ServiceContainer();
container.Register<string, IFoo>((factory, value) => new Foo(value));
var firstFoo = container.GetInstance<string, IFoo>("SomeValue");
var secondFoo = container.GetInstance<string, IFoo>("AnotherValue");

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

public interface IBar { }

public class Bar : IBar
{
    public Bar(Func<string, IFoo> fooFactory)
    {
        var firstFoo = fooFactory("SomeValue");
        var secondFoo = fooFactory("AnotherValue");
    }
}

"Корень композиции" теперь выглядит следующим образом:

var container = new ServiceContainer();
container.Register<string, IFoo>((factory, value) => new Foo(value));
container.Register<IBar, Bar>();
var bar = container.GetInstance<IBar>();

Если речь идет о передаче "статического" примитивного значения в contructor, это просто делается путем регистрации делегата factory, как это.

var container = new ServiceContainer();
container.Register<IFoo>((factory) => new Foo("SomeValue"));
var firstInstance = container.GetInstance<IFoo>();
var secondInstance = container.GetInstance<IFoo>();

Разница в том, что этот подход не позволяет вам передавать значение во время решения. Значение статически указано во время регистрации.

Ответ 2

Вероятно, самый простой вариант с Simple Injector заключается в регистрации делегатом

[Test]
public void Test1()
{
    Container container = new Container();

    container.Register<IClassWithParameter>(() => new ClassWithParameter("SomeValue"));

    var result = container.GetInstance<IClassWithParameter>();
}

public interface IClassWithParameter { }

public class ClassWithParameter : IClassWithParameter
{
    public ClassWithParameter(string parameter)
    {
    }
}

Расширенный вариант для ввода примитивных зависимостей подробно описан здесь

Ответ 3

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

public class Test : ITest
{
   private IFoo _foo;
   public Test(string parameter, IFoo foo)
   {
      _foo = foo;
      ....
   }
}

Теперь вам нужно не только вручную ввести строку, но и Foo. Итак, теперь вы не используете инъекции зависимостей вообще (на самом деле). Также простое состояние инжектора:

Простой инжектор не позволяет вводить примитивные типы (например, целые числа и строка) в конструкторы.

Поэтому они говорят, не делайте этого.

Другим вариантом здесь является использование "Точки расширяемости" для этого сценария.

Для этого вам нужно абстрагировать свои жестко закодированные элементы из ваших вложенных элементов:

public class Test : ITest
{
   private IFoo _foo;
   public Test(IFoo foo)
   {
      _foo = foo;
      ....
   }

  public void Init(string parameter)
  {

  }
}

Теперь вы можете ввести свои зависимые элементы и ваши жестко закодированные элементы:

_container.Register<ITest, Test>();
_container.RegisterInitializer<Test>(instance => {instance.Init("MyValue");});

Если вы добавите еще одну зависимость, ваша инъекция теперь будет работать без необходимости обновления конфигурации:

public class Test : ITest
{
   private IFoo _foo;
   private IBar _bar;
   public Test(IFoo foo, IBar bar)
   {
      _foo = foo;
      _bar = bar;
      ....
   }

  public void Init(string parameter)
  {

  }
}