我可以将构造函数参数传递给Unity的Resolve()方法吗?

时间:2009-04-24 18:18:16

标签: c# .net dependency-injection unity-container constructor-injection

我使用Microsoft的Unity进行依赖注入,我想做这样的事情:

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参数的构造函数,我希望Unity使用我传递的上下文初始化存储库。另请注意,IDataContext未在Unity注册(我不想要IDataContext的3个实例。)

7 个答案:

答案 0 :(得分:67)

截至今天,他们已添加此功能:

这是最新的下降:

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

答案 1 :(得分:35)

&LT; 2美分&gt;

如果您以后决定使用需要多于或少于上下文的其他服务,该怎么办?

构造函数参数和IoC的问题在于参数最终与正在使用的具体类型相关联,而不是作为服务接口定义的合同的一部分。

我的建议是你要么解决上下文,我相信Unity应该有办法让你避免构建它的3个实例,或者你应该考虑一个工厂服务,你有办法构建它对象

例如,如果您稍后决定构建一个完全不依赖于传统数据库的存储库,而是使用XML文件为测试生成虚拟数据,该怎么办?您如何将XML内容提供给该构造函数?

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

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

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

&LT; / 2美分&gt;

答案 2 :(得分:6)

谢谢你们......我的帖子类似于#34; Exist&#34;。见下文:

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

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

答案 3 :(得分:5)

您可以使用InjectionConstructor / InjectionProperty / InjectionMethod,具体取决于ResolvedParameter中的注入体系结构&lt; T&gt;(“name”)获取容器中预先注册的Object的实例。

在您的情况下,此Object必须使用Name注册,对于相同的insance,您需要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")));

答案 4 :(得分:3)

答案非常简短:没有。 Unity目前无法将参数传递给非常量或注入的构造函数,这是我能够找到的。恕我直言,这是它失踪的最大的一件事,但我认为这是设计而不是遗漏。

正如Jeff Fritz指出的那样,理论上你可以创建一个自定义生命周期管理器来知道要注入各种类型的上下文实例,但这是一个硬编码级别,这似乎可以避免在第一个中使用Unity或DI的目的地点。

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

答案 5 :(得分: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

希望这也有帮助

答案 6 :(得分:0)

NotDan,我想你可能已经在对lassevk的评论中回答了你自己的问题。

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

听起来ContainerControlledLifetimeManager对象会为您提供所需的实例管理。有了LifetimeManager,Unity应该将IDataContext的相同实例添加到需要IDataContext依赖关系的所有对象。