Простой инжектор позволяет передавать параметры конструктору при его разрешении? Я хотел бы знать, делают ли обе эти структуры то, что делают Unity ResolverOverride или DependencyOverride.
Как передать параметр конструктору с помощью Simple Injector?
Ответ 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)
{
}
}