С Unity как мне ввести именованную зависимость в конструктор?
У меня есть 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;
.....
}
есть ли способ заставить мой поддельный код работать?
4 ответов:
вы можете настроить зависимости с именами или без них в 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чтобы не зависеть напрямую от Единство.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 когда-либо снова при добавлении новых стратегий в будущем.
это очень просто. Очень чистый, и я сохранил зависимость от Unity до строгого минимума. Единственный раз, когда я коснусь StrategyResolver, - это если я решу изменить контейнерную технологию, что очень маловероятно случаться.
надеюсь, что это помогает!
Edit: мне не очень нравится принятый ответ, потому что когда вы используете
Dependencyатрибут в конструкторе вашего сервиса у вас на самом деле есть жесткая зависимость от Unity. ЭлементDependencyатрибут является частью Библиотеки Unity. В этот момент Вы могли бы также передатьIUnityContainerзависимость везде.Я предпочитаю, чтобы мои классы обслуживания зависели от объектов, которыми я полностью владею, вместо того, чтобы иметь жесткую зависимость от внешнего библиотеки все на месте. Также с помощью
Dependencyатрибут делает подписи конструкторов менее чистыми и простыми.кроме того, этот метод позволяет разрешать именованные зависимости во время выполнения без необходимости жестко кодировать именованные зависимости в конструкторе, в файле конфигурации приложения или использовать
InjectionParameterкоторые являются все методы, которые требуют знать, что именованная зависимость для использования во время разработки.редактировать (2016-09-19): Для тех, кто может задаться вопросом, контейнер будет знать, чтобы передать себя, когда вы запрашиваете
IUnityContainerкак зависимость, как показано вStrategyResolverподпись конструктора.
вы должны быть в состоянии использовать ParameterOverrides
var repository = IOC.Container.Resolve<IRepository>("Client"); var clientModel = IOC.Container.Resolve<ClientModel>(new ParameterOverrides<ClientModel> { {"dataAccess", repository } } );изменить: Я не уверен, почему вы передаете UnityContainer-лично мы вводим наши зависимости в сам конструктор (что является "нормальным" из того, что я видел). Но независимо от этого вы можете указать имя в своем RegisterType и разрешить методы.
IOC.Container.RegisterType<IRepository, GenericRepository>("Client"); IOC.Container.Resolve<IRepository>("Client");и это даст вам тип, который вы зарегистрировали для этого имени.
Не делайте этого - просто создайте
class ClientRepository : GenericRepository { }и использовать систему типов.
Comments