推迟使用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;
});

推迟使用Autofac登记物业

为了能够掌握注册问题,我经常发现在代码中手工构造所需的对象图非常有用。如果不使用DI容器,这就是您希望实现的:

var p = new P();
var a = new A(new B(p)) { P = p };

您可以看到,在整个图中重用P的实例来实现这一点。有了这些知识,我们现在可以确定你需要做什么来实现你想要的。

因此,解决方案是配置autofacc以重用相同的P实例。既然您将A注册为SingleInstance,那么除了将P注册为SingleInstance之外,没有其他选择,否则您将处理一个Captive Dependency。

但是如果我们退后一步,我看不出PA的属性的理由。事实上,使用属性注入几乎没有什么好的理由。

应该始终使用构造函数注入。所以你的类应该如下所示:

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