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


91

我正在使用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);

RepositoryA并且RepositoryB都有一个构造函数的IDataContext参数,我想团结与我通过它的上下文初始化存储库。另请注意,该代码IDataContext未在Unity中注册(我不需要3个实例IDataContext)。

Answers:


71

截止到今天,他们已经添加了以下功能:

这是最近的一滴:

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
“类'Microsoft.Practices.Unity.ParameterOverrides'没有类型参数”。我正在使用Unity 3.5;该代码仅对旧版本的Unity有效吗?
Thomas Levesque 2014年

这个对我有用。注意:您的类必须具有带有“ name”参数和“ address”参数的参数化构造函数。 Foo(string name, int address) { ... }
阿敦

使用Unity 2.1: container.Resolve<IFoo>(new ParameterOverrides { { "name", "bar" }, { "address", 42 } });
mrfelis

38

<2美分>

如果您稍后决定使用需要更多或更少的服务而不只是上下文,该怎么办?

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

我的建议是,您也可以解析上下文,并且我相信Unity应该为您提供一种避免构造3个实例的方法,或者您应该考虑一种可以为您构造对象的工厂服务。

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

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

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

现在,我知道其他IoC容器也对此提供支持,我在自己的第一个版本中也对此提供了支持,但是我认为它不属于解决步骤。

</ 2美分>


3
我明白了您的观点并同意您的观点,但是我仍然需要RepositoryA和RepositoryB的实例具有相同的IDataContext,这需要与RepositoryC不同。还要注意,IRepositoryA和IRepositoryB具有IDataContext的属性。我将稍微更新示例代码。
NotDan

2
好点。我本打算向构造函数添加一个字符串参数,但是在查看了这一点之后,我决定将其设为完整的对象。此时,它仅由字符串组成,但是我已经知道如何为它添加更多有用的属性
Santosh Benjamin 2010年

9

谢谢大家...我的帖子与“ Exist”的帖子相似。见下文:

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

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

5

您可以根据自己的注入架构在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")));

4
您确定此代码吗?它不会编译... Resolve需要的集合ResolverOverride,并且InjectionConstructor不是ResolverOverride
Thomas Levesque 2014年

是的,它看起来不对。尽管团结本来应该是那样设计的。如果参数名称更改,则一切都会中断
Frank Q.17年

3

非常简短的答案是:不。目前,Unity无法将我无法找到的非恒定或注入参数传递给构造函数。恕我直言,这是它最大的缺失,但是我认为这是设计使然,而不是疏忽。

正如Jeff Fritz指出的那样,从理论上讲,您可以创建一个自定义的生存期管理器,该管理器知道将哪种上下文实例注入到各种类型中,但这是一个硬编码级别,这似乎消除了最初使用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

希望这也有帮助


0

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

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.