У меня есть IRespository
, зарегистрированный дважды (с именами) в следующем коде:
// Setup the Client Repository
IOC.Container.RegisterType<ClientEntities>(new InjectionConstructor());
IOC.Container.RegisterType<IRepository, GenericRepository>
("Client", new InjectionConstructor(typeof(ClientEntities)));
// Setup the Customer Repository
IOC.Container.RegisterType<CustomerEntities>(new InjectionConstructor());
IOC.Container.RegisterType<IRepository, GenericRepository>
("Customer", new InjectionConstructor(typeof(CustomerEntities)));
IOC.Container.RegisterType<IClientModel, ClientModel>();
IOC.Container.RegisterType<ICustomerModel, CustomerModel>();
Но затем, когда я захочу решить эту проблему (чтобы использовать IRepository
) Мне нужно выполнить ручное разрешение, например следующее:
public ClientModel(IUnityContainer container)
{
this.dataAccess = container.Resolve<IRepository>(Client);
.....
}
Я бы хотел разрешить его в конструкторе (точно так же, как IUnityContainer
). Мне нужен способ сказать, в какой именованный тип разрешить.
Примерно так: (ПРИМЕЧАНИЕ: Неверный код)
public ClientModel([NamedDependancy("Client")] IRepository dataAccess)
{
this.dataAccess = dataAccess;
.....
}
Есть ли способ заставить мой поддельный код работать?
Вы можете настроить зависимости с именами или без них в API, атрибутах или через файл конфигурации. Вы не упомянули XML выше, поэтому я предполагаю, что вы используете API.
Чтобы указать контейнеру разрешить именованную зависимость, вам нужно использовать объект InjectionParameter
. Для вашего примера ClientModel
сделайте следующее:
container.RegisterType<IClientModel, ClientModel>(
new InjectionConstructor( // Explicitly specify a constructor
new ResolvedParameter<IRepository>("Client") // Resolve parameter of type IRepository using name "Client"
)
);
Это говорит контейнеру «При разрешении ClientModel
вызовите конструктор, который принимает один параметр IRepository
. При разрешении этого параметра разрешите с помощью имя «Клиент» в дополнение к типу. "
Если вы хотите использовать атрибуты, ваш пример почти работает, вам просто нужно изменить имя атрибута:
public ClientModel([Dependency("Client")] IRepository dataAccess)
{
this.dataAccess = dataAccess;
.....
}
Это очень поздний ответ, но вопрос все еще появляется в Google.
Так или иначе, 5 лет спустя ...
У меня довольно простой подход. Обычно, когда вам нужно использовать «именованную зависимость», это потому, что вы пытаетесь реализовать какой-то шаблон стратегии. В этом случае я просто создаю уровень косвенности между Unity и остальной частью моего кода, называемый StrategyResolver
, чтобы он не зависел напрямую от Unity.
public class StrategyResolver : IStrategyResolver
{
private IUnityContainer container;
public StrategyResolver(IUnityContainer unityContainer)
{
this.container = unityContainer;
}
public T Resolve<T>(string namedStrategy)
{
return this.container.Resolve<T>(namedStrategy);
}
}
Использование:
public class SomeClass: ISomeInterface
{
private IStrategyResolver strategyResolver;
public SomeClass(IStrategyResolver stratResolver)
{
this.strategyResolver = stratResolver;
}
public void Process(SomeDto dto)
{
IActionHandler actionHanlder = this.strategyResolver.Resolve<IActionHandler>(dto.SomeProperty);
actionHanlder.Handle(dto);
}
}
Регистрация:
container.RegisterType<IActionHandler, ActionOne>("One");
container.RegisterType<IActionHandler, ActionTwo>("Two");
container.RegisterType<IStrategyResolver, StrategyResolver>();
container.RegisterType<ISomeInterface, SomeClass>();
Теперь, хорошо, что мне больше никогда не придется прикасаться к StrategyResolver при добавлении новых стратегии в будущем.
1120 Это очень просто. Очень чисто и я держал зависимость от Unity до строгого минимума. Единственный раз, когда я бы коснулся StrategyResolver, - это если я решу изменить контейнерную технологию, что вряд ли произойдет.
Надеюсь, это поможет!
Редактировать: Мне не очень нравится принятый ответ, потому что когда вы используете атрибут Dependency
в конструкторе вашего сервиса, вы на самом деле сильно зависите от Unity. Атрибут Dependency
является частью библиотеки Unity. В этот момент вы также можете передать IUnityContainer
зависимость везде.
Я предпочитаю, чтобы мои классы обслуживания зависели от объектов, которыми я полностью владею, вместо того, чтобы иметь жесткую зависимость от внешней библиотеки повсюду. Также использование атрибута Dependency
делает подписи конструкторов менее понятными и простыми.
Кроме того, этот метод позволяет разрешать именованные зависимости во время выполнения без необходимости жестко кодировать именованные зависимости в конструкторе, в файле конфигурации приложения или использовать InjectionParameter
, которые являются всеми методами, которые требуют знать, какую именованную зависимость использовать при проектировании. время.
Редактировать (2016-09-19): Для тех, кто может задаться вопросом, контейнер будет знать, что он пропустит себя, когда вы запрашиваете IUnityContainer
как зависимость, как показано в сигнатуре конструктора StrategyResolver
.
Редактировать (2018-10-20): Вот еще один способ, просто с использованием фабрики:
public class SomeStrategyFactory : ISomeStrategyFactory
{
private IStrategy _stratA;
private IStrategy _stratB;
public SomeFactory(IStrategyA stratA, IStrategyB stratB)
{
_stratA = stratA;
_stratB = stratB;
}
public IStrategy GetStrategy(string namedStrategy){
if (namedStrategy == "A") return _stratA;
if (namedStrategy == "B") return _stratB;
}
}
public interface IStrategy {
void Execute();
}
public interface IStrategyA : IStrategy {}
public interface IStrategyB : IStrategy {}
public class StrategyA : IStrategyA {
public void Execute(){}
}
public class StrategyB : IStrategyB {
public void Execute() {}
}
Использование:
public class SomeClass : ISomeClass
{
public SomeClass(ISomeStrategyFactory strategyFactory){
IStrategy strat = strategyFactory.GetStrategy("HelloStrategy");
strat.Execute();
}
}
Регистрация:
container.RegisterType<ISomeStrategyFactory, SomeStrategyFactory>();
container.RegisterType<IStrategyA, StrategyA>();
container.RegisterType<IStrategyB, StrategyB>();
container.RegisterType<ISomeClass, SomeClass>();
Это второе предложение - то же самое, но с использованием шаблона фабричного проектирования.
Надеюсь, это поможет!
Вы должны иметь возможность использовать ParameterOverrides
var repository = IOC.Container.Resolve<IRepository>("Client");
var clientModel = IOC.Container.Resolve<ClientModel>(new ParameterOverrides<ClientModel> { {"dataAccess", repository } } );
. Редактировать: я не уверен, почему вы обмениваетесь UnityContainer - лично мы внедряем наши зависимости в конструктор (что нормально). "из того, что я видел). Но независимо от этого, вы можете указать имя в ваших методах RegisterType и Resolve.
IOC.Container.RegisterType<IRepository, GenericRepository>("Client");
IOC.Container.Resolve<IRepository>("Client");
и он даст вам тип, который вы зарегистрировали для этого имени.