使用Unity如何将一个命名的dependency injection到构造函数中?
我有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); ..... }
我想要做的就是让它在构造函数中parsing(就像IUnityContainer)。 我需要一些方法来说明哪个命名types要parsing。
像这样的东西:( 注意:不是真正的代码)
public ClientModel([NamedDependancy("Client")] IRepository dataAccess) { this.dataAccess = dataAccess; ..... }
有没有办法让我的假代码工作?
您可以在API,属性或configuration文件中configuration具有或不具有名称的依赖关系。 你没有提到上面的XML,所以我假设你正在使用API。
要告诉容器parsing一个命名的依赖关系,你需要使用一个InjectionParameter对象。 对于您的ClientModel示例,请执行以下操作:
container.RegisterType<IClientModel, ClientModel>( new InjectionConstructor( // Explicitly specify a constructor new ResolvedParameter<IRepository>("Client") // Resolve parameter of type IRepository using name "Client" ) );
这告诉容器“当parsingClientModel时,调用带有单个IRepository参数的构造函数,parsing该参数时,除了types之外,还要使用名称”Client“来parsing。
如果你想使用属性,你的例子几乎可以工作,你只需要改变属性名称:
public ClientModel([Dependency("Client")] IRepository dataAccess) { this.dataAccess = dataAccess; ..... }
这是一个非常晚的反应,但问题仍然显示在谷歌。
所以无论如何,5年后…
我有一个非常简单的方法。 通常当你需要使用“命名依赖”时,这是因为你试图实现某种策略模式。 在这种情况下,我只是简单地在Unity和其余的代码中创build一个间接级别,称为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了。
这很简单。 非常干净,我把对Unity的依赖严格控制在最低限度。 唯一一次我会触及StrategyResolver的是,如果我决定改变不太可能发生的容器技术。
希望这可以帮助!
编辑:我真的不喜欢接受的答案,因为当你在服务的构造函数中使用Dependency
属性,你实际上有一个很强的依赖。 Dependency
属性是Unity库的一部分。 在这一点上,不妨到处传递一个IUnityContainer
依赖关系。
我更喜欢让我的服务类依赖于我完全拥有的对象,而不是依赖于外部库。 另外使用Dependency
属性使得构造函数的签名更加简洁。
此外,这种技术允许在运行时parsing命名的依赖关系,而不必在构造器,应用程序configuration文件中使用硬编码命名的依赖关系,或者使用InjectionParameter
,这些都是需要知道在devise时使用哪个命名依赖关系的方法。
编辑(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和Resolve方法中指定一个名称。
IOC.Container.RegisterType<IRepository, GenericRepository>("Client"); IOC.Container.Resolve<IRepository>("Client");
它会给你你注册这个名字的types。