C# 我可以将构造函数参数传递给 Unity 的 Resolve() 方法吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/787001/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I pass constructor parameters to Unity's Resolve() method?
提问by NotDan
I am using Microsoft's Unity for dependency injection and I want to do something like this:
我正在使用微软的 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
and RepositoryB
both have a constructor that takes an IDataContext
parameter, and I want Unity to initialize the repository with the context that I pass it. Also note that IDataContext
is not registered with Unity (I don't want 3 instances of IDataContext
).
RepositoryA
并且RepositoryB
两者都有一个带IDataContext
参数的构造函数,我希望 Unity 使用我传递的上下文初始化存储库。另请注意,IDataContext
未在 Unity 中注册(我不想要 3 个 实例IDataContext
)。
采纳答案by Exist
As of today they have added this functionality:
截至今天,他们已添加此功能:
It's in the latest drop here:
这是最新的下降:
http://unity.codeplex.com/SourceControl/changeset/view/33899
http://unity.codeplex.com/SourceControl/changeset/view/33899
Discussion on it here:
在这里讨论:
http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434
http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434
Example:
例子:
container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"
回答by Lasse V. Karlsen
< 2 cents>
<2 美分>
What if you later on decide to use a different service that requires more or less than just the context?
如果您后来决定使用需要更多或更少上下文的不同服务怎么办?
The problem with constructor parameters and IoC is that the parameters are ultimately tied to the concrete type being used, as opposed to being part of the contract that the service interface defines.
构造函数参数和 IoC 的问题在于,参数最终与所使用的具体类型相关联,而不是作为服务接口定义的契约的一部分。
My suggestion would be that you either resolve the context as well, and I believe Unity should have a way for you to avoid constructing 3 instances of it, or you should consider a factory service that has a way for you to construct the object.
我的建议是你要么解决上下文,我相信 Unity 应该有一种方可以让你避免构造它的 3 个实例,或者你应该考虑一个工厂服务,它可以让你构造对象。
For instance, what if you later on decide to construct a repository that doesn't rely on a traditional database at all, but instead use an XML file to produce dummy-data for the test? How would you go about feeding the XML content to that constructor?
例如,如果您后来决定构建一个完全不依赖传统数据库的存储库,而是使用 XML 文件为测试生成虚拟数据,该怎么办?您将如何将 XML 内容提供给该构造函数?
IoC is based around decoupling code, by tying in the type and semantics of the arguments to the concrete types, you really haven't done the decoupling correctly, there's still a dependency.
IoC 基于解耦代码,通过将参数的类型和语义绑定到具体类型,您确实没有正确完成解耦,仍然存在依赖关系。
"This code can talk to any type of repository possibly, as long as it implements this interface.... Oh, and uses a data context".
“这段代码可以与任何类型的存储库对话,只要它实现了这个接口......哦,并使用数据上下文”。
Now, I know that other IoC containers have support for this, and I had it in my first version of my own as well, but in my opinion, it doesn't belong with the resolution step.
现在,我知道其他 IoC 容器对此也有支持,而且我在我自己的第一个版本中也有它,但在我看来,它不属于解决步骤。
< /2 cents>
</2 美分>
回答by Jeff Fritz
NotDan, I think you may have answered your own question in comments to lassevk.
NotDan,我想你可能已经在对 lassevk 的评论中回答了你自己的问题。
First, I would use a LifetimeManager to manage the lifecycle and number of instances of IDataContext that Unity creates.
http://msdn.microsoft.com/en-us/library/cc440953.aspx
首先,我将使用 LifetimeManager 来管理 Unity 创建的 IDataContext 实例的生命周期和数量。
http://msdn.microsoft.com/en-us/library/cc440953.aspx
It sounds like the ContainerControlledLifetimeManager
object will give you the instance management that you need. With that LifetimeManager in place, Unity should add the same instance of the IDataContext to all objects that require an IDataContext dependency.
听起来该ContainerControlledLifetimeManager
对象将为您提供所需的实例管理。有了 LifetimeManager,Unity 应该将 IDataContext 的相同实例添加到所有需要 IDataContext 依赖项的对象。
回答by Neil Hewitt
The very short answer is: no. Unity currently has no way to pass parameters into the constructor that aren't constant or injected, that I have been able to find. IMHO that's the single biggest thing it's missing, but I think it is by design rather than by omission.
非常简短的回答是:不。Unity 目前无将参数传递到非常量或注入的构造函数中,我已经找到了。恕我直言,这是它缺少的最大的事情,但我认为这是设计而不是遗漏。
As Jeff Fritz notes, you could in theory create a custom lifetime manager that knows which context instance to inject into various types, but that's a level of hard-coding which seems to obviate the purpose of using Unity or DI in the first place.
正如 Jeff Fritz 指出的那样,理论上您可以创建一个自定义生命周期管理器,它知道将哪个上下文实例注入到各种类型中,但这是一个硬编码级别,这似乎首先消除了使用 Unity 或 DI 的目的。
You could take a small step back from full DI and make your repository implementations responsible for establishing their own data contexts. The context instancecan still be resolved from the container but the logic for deciding which one to use would have to go into the implementation of the repository. It's not as pure, certainly, but it would get rid of the problem.
您可以从完全 DI 中退后一小步,让您的存储库实现负责建立自己的数据上下文。上下文实例仍然可以从容器中解析,但决定使用哪一个的逻辑必须进入存储库的实现。它当然不是那么纯粹,但它会解决这个问题。
回答by Samuel Carrijo
Another alternative you could use (don't really know if it is a good practice or not) is creating two containers and registering an instance for each:
您可以使用的另一种替代方(不知道这是否是一个好习惯)是创建两个容器并为每个容器注册一个实例:
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
hope this helps too
希望这也有帮助
回答by Trecenti
You can use InjectionConstructor / InjectionProperty / InjectionMethod depending on your Injection Architecture within the ResolvedParameter< T >("name") to get a instance of a pre-registered Object in the container.
您可以使用 InjectionConstructor / InjectionProperty / InjectionMethod 根据您在 ResolvedParameter< T >("name") 中的注入架构来获取容器中预注册对象的实例。
In your case this Object must be registered with a Name, and for the same insance you need ContainerControlledLifeTimeManager() as the LifeTimeManager.
在您的情况下,此对象必须使用名称注册,并且对于相同的实例,您需要 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")));
回答by Kwex
Thanks guys ... mine is similar to the post by "Exist". See below:
谢谢大家......我的类似于“存在”的帖子。见下文:
IUnityContainer container = new UnityContainer();
container.LoadConfiguration();
_activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
{
new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
});