推迟使用Autofac登记物业
本文关键字:Autofac 推迟 | 更新日期: 2023-09-27 18:13:07
我正在尝试使用Autofac实现以下依赖注入场景。
假设我有三个类,A, B和p。类A拥有一个类型为p的属性,并且有一个对B的引用,需要在运行时注入。
class A
{
private B _b;
public P Prop { get; set; }
InitializeProp()
{ ... }
}
同时,类B依赖于p的一个实例:
class B
{
private P _p;
}
现在,最重要的细节:我需要以某种方式向B注入p的实例。然而,该实例必须是来自类A的Prop,只有在调用A中的InitializeProp()之后才初始化。假设InitializeProp()可以在对象生命周期的后期调用,而不是a的构造函数。
使用autoface是否可以实现此场景?
我试着做这样的事情,但我得到一个循环引用异常,大概是当B进一步解决时:
containerBuilder.RegisterType<A>().SingleInstance();
containerBuilder.Register<Func<P>>(c =>
{
var a = c.Resolve<A>();
return () => a.Prop;
});
为了能够掌握注册问题,我经常发现在代码中手工构造所需的对象图非常有用。如果不使用DI容器,这就是您希望实现的:
var p = new P();
var a = new A(new B(p)) { P = p };
您可以看到,在整个图中重用P
的实例来实现这一点。有了这些知识,我们现在可以确定你需要做什么来实现你想要的。
因此,解决方案是配置autofacc以重用相同的P
实例。既然您将A
注册为SingleInstance
,那么除了将P
注册为SingleInstance
之外,没有其他选择,否则您将处理一个Captive Dependency。
但是如果我们退后一步,我看不出P
是A
的属性的理由。事实上,使用属性注入几乎没有什么好的理由。
应该始终使用构造函数注入。所以你的类应该如下所示:
class A { public A(B b, P p) { } }
class B { public B(P p) { } }
这完全消除了配置问题,因为您可以简单地执行以下操作:
containerBuilder.RegisterType<A>().SingleInstance();
containerBuilder.RegisterType<B>().SingleInstance();
containerBuilder.RegisterType<P>().SingleInstance();
最终我弄明白了,原来Autofac比我想象的要聪明。
没有必要显式地注册p的Func
,而是有这样一个简化的注册:
builder.RegisterType<A>().SingleInstance();
builder.Register(c =>
{
var a = c.Resolve<A>();
return a.Property;
});
builder.RegisterType<B>();
现在在主程序中,我可以做以下操作:
var a = container.Resolve<A>();
a.InitializeProperty();
a.Execute(); // calls B