我可以传递构造参数到Unity的Resolve()方法吗?
我正在使用微软的Unity进行dependency injection,我想要做这样的事情:
IDataContext context = _unityContainer.Resolve<IDataContext>(); var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2);
RepositoryA
和RepositoryB
都有一个构造函数,它需要一个IDataContext
参数,我希望Unity使用我传递的上下文初始化存储库。 另外请注意, IDataContext
没有注册Unity(我不想要3个IDataContext
实例)。
截至今天,他们已经添加了这个function:
这是最近的一次下降:
http://unity.codeplex.com/SourceControl/changeset/view/33899
在这里讨论一下:
http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434
例:
container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"
<2美分>
如果你以后决定使用不同的服务,那么需要的不仅仅是上下文呢?
构造函数参数和IoC的问题在于参数最终与所使用的具体types绑定,而不是服务接口定义的合约的一部分。
我的build议是,你要么解决上下文,我相信Unity应该有一个方法让你避免构build它的3个实例,或者你应该考虑一个工厂服务,有一个方法来构build对象。
例如,如果你稍后决定构build一个根本不依赖于传统数据库的存储库,而是使用XML文件为testing生成虚拟数据呢? 如何将XML内容提供给构造函数?
IoC基于解耦代码,通过将参数的types和语义绑定到具体types上,您确实没有正确解耦,仍然存在依赖关系。
“这个代码可以与任何types的存储库进行通信,只要它实现了这个接口….哦,并使用数据上下文”。
现在,我知道其他的IoC容器也有这个支持,而且我自己也有自己的第一个版本,但在我看来,它不属于解决步骤。
</ 2 cents>
你可以在ResolvedParameter <T>(“name”)中使用InjectionConstructor / InjectionProperty / InjectionMethod来获取容器中预先注册的对象的一个实例。
在你的情况下,这个对象必须注册一个名称,对于同样的情况,你需要将ContainerControlledLifeTimeManager()作为LifeTimeManager。
_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager()); _unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB"); var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor( new ResolvedParameter<IDataContext>("DataContextA"))); var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor( new ResolvedParameter<IDataContext>("DataContextA"))); var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor( new ResolvedParameter<IDataContext>("DataContextB")));
很简短的答案是:不。 Unity目前没有办法将parameter passing到构造函数中,而这些构造函数并不是常量或注入的,我已经能够find它了。 恕我直言,这是它最大的缺失,但我认为这是通过devise而不是遗漏。
正如Jeff Fritz所指出的那样,你可以在理论上创build一个自定义的生命周期pipe理器,知道哪个上下文实例要注入不同的types,但是这是一个硬编码的层次,似乎无法摆脱首先使用Unity或DI的目的。
您可以从完整的DI中退出一小步,并使您的存储库实现负责build立自己的数据上下文。 上下文实例仍然可以从容器中parsing,但决定使用哪一个的逻辑将不得不进入存储库的实现。 当然不是那么纯粹,但是它会摆脱这个问题。
感谢球员…我的是类似的“存在”的职位。 见下文:
IUnityContainer container = new UnityContainer(); container.LoadConfiguration(); _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[] { new ParameterOverride("activeDirectoryServer", "xyz.adserver.com") });
你可以使用的另一种select(不知道是否是一个好的做法)是创build两个容器并为每个容器注册一个实例:
IDataContext context = _unityContainer.Resolve<IDataContext>(); _unityContainer.RegisterInstance(context); var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context //declare _unityContainer2 IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance _unityContainer2.RegisterInstance(context2); var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance
希望这也有帮助
NotDan,我想你可能已经在lassevk的评论中回答了你自己的问题。
首先,我将使用LifetimeManager来pipe理Unity创build的IDataContext实例的生命周期和数量。
http://msdn.microsoft.com/en-us/library/cc440953.aspx
这听起来像ContainerControlledLifetimeManager
对象会给你你需要的实例pipe理。 使用LifetimeManager时,Unity应该将IDataContext的实例添加到需要IDataContext依赖项的所有对象。