克隆现有的AutoFac对象,但一次注册除外

时间:2014-09-15 02:22:56

标签: c# inversion-of-control autofac

说我在AutoFac(简化)中注册了以下内容:

对象A - >对象B - >对象C - >对象D

现在假设我想创建第二个对象A(让它称之为对象P),它是对象A的虚拟克隆,除了一个区别:

对象A - >对象B - > 对象F - >对象D

有没有办法获取现有的AutoFac对象并以这种方式克隆它?我在"现实生活中工作的对象图"比这个例子复杂了许多个数量级,如果没有必要,我不会复制一堆注册逻辑。

1 个答案:

答案 0 :(得分:2)

虽然你可能会使用component metadata来实现这种情况,但最简单的方法是使用嵌套的生命周期范围并覆盖注册。

当您开始新的生命周期范围时,您可以传入一个lambda表达式,该表达式允许您即时向该范围添加新注册。此时你将覆盖"对象C"注册"对象F。"

这是一个有效的例子。首先,让我们定义一些接口和实现。您会注意到层次结构中的第三项服务IThird有两个实现 - ObjectCObjectF - 以匹配您的问题:

public interface IFirst
{
    ISecond Child { get; }
    void WriteHierarchy();
}

public interface ISecond
{
    IThird Child { get; }
}

public interface IThird
{
    IFourth Child { get; }
}

public interface IFourth
{
}

public class ObjectA : IFirst
{
    public ObjectA(ISecond child)
    {
        this.Child = child;
    }

    public ISecond Child { get; private set; }

    public void WriteHierarchy()
    {
        Console.WriteLine("{0} -> {1} -> {2} -> {3}",
            this.GetType().Name,
            this.Child.GetType().Name,
            this.Child.Child.GetType().Name,
            this.Child.Child.Child.GetType().Name);
    }
}

public class ObjectB : ISecond
{
    public ObjectB(IThird child)
    {
        this.Child = child;
    }

    public IThird Child { get; private set; }
}

public class ObjectC : IThird
{
    public ObjectC(IFourth child)
    {
        this.Child = child;
    }

    public IFourth Child { get; private set; }
}

public class ObjectF : IThird
{
    public ObjectF(IFourth child)
    {
        this.Child = child;
    }

    public IFourth Child { get; private set; }
}

public class ObjectD : IFourth
{
}

有了这个,您可以看到我们要做的就是解决该顶级项目IFirst,并且我们会写出层次结构。

这是显示" swap"的实际工作代码。层次结构中的第三个项目:

var builder = new ContainerBuilder();
builder.RegisterType<ObjectA>().As<IFirst>();
builder.RegisterType<ObjectB>().As<ISecond>();
builder.RegisterType<ObjectC>().As<IThird>();
builder.RegisterType<ObjectD>().As<IFourth>();

var container = builder.Build();

// It's always good to use lifetime scopes and not
// resolve directly from a container. You can see
// here that I'm not doing anything special - this
// lifetime scope will have the "default registrations."
using(var scope = container.BeginLifetimeScope())
{
    // This will print:
    // ObjectA -> ObjectB -> ObjectC -> ObjectD
    var obj = scope.Resolve<IFirst>();
    obj.WriteHierarchy();
}

// You can pass override registrations when you begin
// a new lifetime scope. In this case, I'm overriding
// the one service type deep in the hierarchy.
using(var scope = container.BeginLifetimeScope(
    b => b.RegisterType<ObjectF>().As<IThird>()))
{
    // This will print:
    // ObjectA -> ObjectB -> ObjectF -> ObjectD
    var obj = scope.Resolve<IFirst>();
    obj.WriteHierarchy();
}