使用Autofac推迟登记财产

时间:2016-10-13 16:01:36

标签: c# .net dependency-injection autofac

我尝试使用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的构造函数。

这种情况是否可以通过Autofac实现?

我尝试过这样的事情,但是我得到了一个循环引用异常,大概是当B进一步解决时:

containerBuilder.RegisterType<A>().SingleInstance();

containerBuilder.Register<Func<P>>(c =>
{
    var a = c.Resolve<A>();
    return () => a.Prop;
});

2 个答案:

答案 0 :(得分:2)

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

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

您可以看到,P的实例在整个图表中被重用以实现此目的。有了这些知识,我们现在可以确定您需要做什么才能实现您想要的目标。

因此,解决方案是将Autofac配置为重用P的相同实例。由于您将A注册为SingleInstance,因此除PSingleInstance注册外,别无其他选择,否则您将处理Captive Dependency

但如果我们后退一步,我认为P没有理由成为A的财产。事实上,使用属性注入有hardly ever a good reason

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

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();

答案 1 :(得分:0)

所以最终我弄清楚了,原来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