В этом уроке мы рассмотрим несколько различных способов использования пользовательских параметров конструктора при разрешении экземпляра в Unity:
- С помощью встроенного ParameterOverride
- Создавая собственный ResolverOverride.
Фон
Когда вы используете DI-контейнер, такой как Unity , вам обычно не нужно беспокоиться о том, как контейнер разрешает новый экземпляр. Вы настроили контейнер, и контейнер будет действовать в зависимости от вашей конфигурации. Но могут быть случаи, когда вы передаете пользовательские параметры конструктора для операции разрешения. Некоторые могут утверждать, что это кричит о плохой архитектуре, но есть ситуации, например, перенос DI-контейнера в унаследованную систему, которая может требовать такого рода действий.
Решенный класс
В этом уроке мы решаем следующий тестовый класс:
|
public class MyClass { public string Hello { get; set; } public int Number { get; set; } public MyClass(string hello, int number) { Hello = hello; Number = number; } |
Он регистрируется в контейнере с помощью метода RegisterType и без передачи каких-либо параметров:
var unity = new UnityContainer(); unity.RegisterType<MyClass>(); |
Итак, давайте посмотрим, как мы можем передать переменные «hello» и «number» для конструктора MyClass ‘при вызове Unity’s Resolve.
Unity ResolverOverride
Unity позволяет нам передавать ResolverOverride, когда вызывается метод Resolve- контейнера . ResolverOverride является абстрактным базовым классом, и Unity поставляется с несколькими из них встроенными. Одним из них является ParameterOverride, который «позволяет переопределять именованный параметр, передаваемый в конструктор».
Таким образом, зная, что нам нужно передать строку с именем «hello» и целое число с именем «number», мы можем разрешить экземпляр с помощью ParameterOverride:
[Test] public void Test() { var unity = new UnityContainer(); unity.RegisterType<MyClass>(); var myObj = unity.Resolve<MyClass>(new ResolverOverride[] { new ParameterOverride("hello", "hi there"), new ParameterOverride("number", 21) }); Assert.That(myObj.Hello, Is.EqualTo("hi there")); Assert.That(myObj.Number, Is.EqualTo(21)); } |
Мы передаем в двух случаях ParameterOverride. Оба из них принимают имя и значение параметра.
Custom ResolverOverride: OrderedParametersOverride
Но что, если вам не нравится передавать имена параметров и вместо этого вы хотите передать только значения параметров в правильном порядке? Для этого мы можем создать собственный ResolverOverride. Вот один из способов сделать это:
public class OrderedParametersOverride : ResolverOverride { private readonly Queue<InjectionParameterValue> parameterValues; public OrderedParametersOverride(IEnumerable<object> parameterValues) { this.parameterValues = new Queue<InjectionParameterValue>(); foreach (var parameterValue in parameterValues) { this.parameterValues.Enqueue(InjectionParameterValue.ToParameter(parameterValue)); } } public override IDependencyResolverPolicy GetResolver(IBuilderContext context, Type dependencyType) { if (parameterValues.Count < 1) return null; var value = this.parameterValues.Dequeue(); return value.GetResolverPolicy(dependencyType); } |
Значения параметров передаются через конструктор и помещаются в очередь. Когда контейнер разрешает экземпляр, параметры используются в том порядке, в котором они были переданы OrderedParametersOverride.
Вот пример использования нового OrderedParametersOverride:
[Test] public void TestOrderedParametersOverride() { var unity = new UnityContainer(); unity.RegisterType<MyClass>(); var myObj = unity.Resolve<MyClass>(new OrderedParametersOverride(new object[] {"greetings", 24 })); Assert.That(myObj.Hello, Is.EqualTo("greetings")); Assert.That(myObj.Number, Is.EqualTo(24)); } |
Образец кода
Приведенные выше примеры можно найти на GitHub.