我在构造函数上实现了Unity注入。我有以下内容:
interface IA
{
DoSomething();
}
class A : IA
{
private List<MyType> List;
public A(List<MyType> list)
{
this.List = list;
}
DoSomething()
{
// do something with this.List
}
}
interface IB
{
List<MyType> GetList();
}
class B : IB
{
public List<MyType> GetList() { }
}
class C
{
private A MyA;
public C(IB b)
{
this.MyA = new A(b.GetList());
}
public DoSomethingInA()
{
this.MyA.DoSomething();
}
}
我想删除&#34;新的A()&#34;在类C的构造函数中并使用IA的注入但我不知道如何在构造函数中注册接收类型IA的A实例的属性而不是实例本身。
我无法改变A的实施!列表&lt;&gt;应该在构造函数中收到。
提前致谢!
答案 0 :(得分:1)
类C
的构造函数做得太多; injector constructors should be simple。因此,不要在构建对象图时调用GetList
,而是将其推迟到稍后时刻,只需在IB
和A
注入C
,如下所示:
class A : IA
{
private IB b;
public A(IB b) {
this.b = b;
}
DoSomething() {
var list = this.b.GetList();
// do something with this.List
}
}
class C
{
private IB b;
public C(IB b) {
this.b = b;
}
}
这简化了您的注册和代码,并允许您compose object graphs with confidence。
<强>更新强>
如果类型不受控制,您应该将其视为第三方类型。通常,您应该小心让容器自动连接这种类型,因为维护该类型的人可能会为该类型添加新的构造函数,这可能会破坏您的DI注册(更多信息here)。
因此,不要让容器自动连接该类型,而是注册一个创建该第三方类型实例的lambda表达式。例如:
container.Register<IA>(new InjectionFactory(c => new A(c.Resolve<IB>().GetList())));
请注意,在这种情况下,在构建对象图时,您仍然做得太多,并且(取决于GetList
在封面下的内容)可能会更难以验证正确性图表。
因此,您正在使用在构造期间依赖于某些运行时类型的第三方类型,您可能需要考虑推迟该类型的创建。如果您为IA
创建代理类,则可以延迟A
的创建,而无需应用程序知道任何相关内容。该代理可能看起来像这样:
class DelayedAProxy : IA
{
private readonly Lazy<IA> a;
public DelayedAProxy(Lazy<IA> a) {
this.a = a;
}
public DoSomething() {
this.a.Value.DoSomething();
}
}
您可以按如下方式注册:
container.Register<IA>(new InjectionFactory(c =>
{
var lazy = new Lazy<IA>(() => new A(c.Resolve<IB>().GetList()));
new DelayedAProxy(lazy);
}));
此处我们不直接注册A
,而是注册DelayedAProxy
,而该代理只会在第一次执行A
时创建DoSomething
,这将在创建完整的对象图之后。
或者,您的代理也可以依赖IB
并在内部创建惰性。这就是:
class DelayedAProxy : IA
{
private readonly Lazy<IA> a;
public DelayedAProxy(IB b) {
this.a = new Lazy<IA>(() => new A(b.GetList()));
}
public DoSomething() {
this.a.Value.DoSomething();
}
}
这样做的好处是DelayedAProxy
的注册变得更加容易:
container.RegisterType<IA, DelayedAProxy>();
虽然看起来在这种情况下DelayedAProxy
构造函数再次做了很多,实际上它只是用委托创建了Lazy。只有在构建代理后才会调用GetList
。
答案 1 :(得分:0)
我最终改变了设计并使用方法而不是构造函数注入依赖项,如:
interface IA
{
Initialize(List<something> list);
DoSomething();
}
class C
{
private IA MyA;
public C(IB b, IA a)
{
this.MyA = a;
this.MyA.Initialize(b.GetList());
}
public DoSomethingInA()
{
this.MyA.DoSomething();
}
}
初始化在构造函数中完成,以减少当前代码调用DoSomething()的影响,也可能是:
public DoSomethingInA()
{
this.MyA.DoSomething(b.GetList());
}
但正如我所说,它对现有代码的影响要大得多。