93

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

4

7 回答 7

72

截至今天,他们已经添加了这个功能:

这是最新的下降:

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 } });"
于 2009-09-21T23:52:47.660 回答
39

< 2 美分>

如果您后来决定使用需要更多或更少不仅仅是上下文的不同服务怎么办?

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

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

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

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

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

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

</2 美分>

于 2009-04-24T18:48:02.097 回答
10

谢谢大家...我的类似于“存在”的帖子。见下文:

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

        _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
        {
            new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
        });
于 2014-10-29T15:43:22.737 回答
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")));
于 2010-04-28T19:02:06.330 回答
3

非常简短的回答是:不。Unity 目前无法将参数传递给我能够找到的非常量或注入的构造函数。恕我直言,这是它缺少的最大的东西,但我认为这是设计而不是遗漏。

正如 Jeff Fritz 所指出的,理论上您可以创建一个自定义生命周期管理器,它知道将哪个上下文实例注入到各种类型中,但这是一种硬编码,它似乎首先排除了使用 Unity 或 DI 的目的。

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

于 2009-04-29T12:54:17.740 回答
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

希望这也有帮助

于 2009-05-15T12:02:27.970 回答
0

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

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

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

于 2009-04-28T10:18:17.360 回答