78

我使用微软的Unity依赖注入和我想要做这样的事情:我可以将构造函数参数传递给Unity的Resolve()方法吗?

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); 

RepositoryARepositoryB都有一个构造函数的IDataContext参数,我想统一初始化与上下文信息库我通过它。还请注意,IDataContext未注册Unity(我不想要3个IDataContext)。

回答

33

< 2美分>

如果您稍后决定使用不同的服务,需要什么不仅仅是方面多还是少?

构造函数参数和IoC的问题是参数最终绑定到正在使用的具体类型,而不是服务接口定义的合约的一部分。

我的建议是你要么解决上下文,我相信Unity应该有一种方法让你避免构建它的3个实例,或者你应该考虑一个工厂服务,它有一个方法来构造物体。例如,如果您稍后决定构建一个根本不依赖传统数据库的存储库,而是使用XML文件为测试生成虚拟数据,会出现什么情况呢?如何将XML内容提供给构造函数?

IoC基于解耦代码,通过将参数的类型和语义绑定到具体类型,您确实没有正确解耦,仍然存在依赖关系。

“此代码可以与任何类型的存储库进行通信,只要它实现此接口....哦,并使用数据上下文”。

现在,我知道其他的IoC容器都支持这个功能,而且我也在自己的第一个版本中使用了它,但在我看来,它并不属于解决步骤。

</2美分>

+3

我明白你的意思,并同意你的观点,但是我仍然需要RepositoryA和RepositoryB的情况下,具有相同的IDataContext,这需要比RepositoryC不同。另请注意,IRepositoryA和IRepositoryB具有IDataContext的属性。我会稍微更新示例代码。 – NotDan 2009-04-24 19:24:48

+2

伟大的一点。我正要为构造函数添加一个字符串参数,但在查看了这一点之后,我决定将其设置为一个完整的对象。它只包含此时的字符串,但我已经可以看到如何向其添加更多有用的属性 – 2010-07-09 09:52:37

0

NotDan,我想你可以在注释中lassevk已经回答了你自己的问题。

首先,我将使用LifetimeManager来管理Unity创建的IDataContext实例的生命周期和数量。
http://msdn.microsoft.com/en-us/library/cc440953.aspx

听起来像ContainerControlledLifetimeManager对象会给你你需要的实例管理。使用该LifetimeManager后,Unity应该将IDataContext的相同实例添加到需要IDataContext依赖项的所有对象。

3

很简短的答案是:不。 Unity目前没有办法将参数传递到构造函数中,这些参数并不是常量或注入的,我一直都能找到。恕我直言,这是它最大的缺陷,但我认为这是通过设计而不是遗漏。根据Jeff Fritz的说法,你可以在理论上创建一个定制的生命周期管理器,该管理器知道哪个上下文实例要注入到各种类型中,但这是一个硬编码级别,它似乎可以避免在Unity中使用Unity或DI的目的。第一名。

您可以从完整的DI中退出一小步,并让您的存储库实现负责建立自己的数据上下文。上下文实例仍然可以从容器中解析出来,但决定使用哪一个的逻辑必须进入存储库的实现。这当然不是那么纯粹,但它会摆脱这个问题。

1

您可以使用(真的不知道,如果它是一个很好的做法或不)是创建两个容器和注册一个实例为每个另一种选择:

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 

希望这有助于太

7

您可以使用InjectionConstructor/InjectionProperty/InjectionMethod取决于ResolvedParameter < T内部的注射架构>( “名” )获取容器中预先注册的对象的实例。

在你的情况下,这个对象必须注册一个名称,对于相同的实例,你需要将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"))); 
5

谢谢你们......我的帖子与“Exist”类似。请看下图:

 IUnityContainer container = new UnityContainer(); 
     container.LoadConfiguration(); 

     _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[] 
     { 
      new ParameterOverride("activeDirectoryServer", "xyz.adserver.com") 
     }); 
相关问题