Autofac使用不同分辨率解析内部依赖项

时间:2019-05-07 07:16:32

标签: autofac

让我们假设以下课程

class Foo : IFoo {
    Foo(IBar bar) {}
}

class Bar : IBar {
    Bar(IBaz baz)       
}

我的容器已设置好,因此您可以通过密钥区分IBaz。

builder.RegisterType<Baz1>().Keyed<IBaz>("1");    
builder.RegisterType<Baz2>().Keyed<IBaz>("2");

现在,我想创建两个注入了IFoo的类,但是更进一步,它们需要注入Baz1或Baz2。

class MyClassA {
    MyClassA(IFoo foo) {
        var baz = foo.GetBar().GetBaz();
        //baz should be of type Baz1 
    }
}

class MyClassB {
    MyClassB(IFoo foo) {
       var baz = foo.GetBar().GetBaz();
       //baz should be of type Baz2
    }  
}

如何配置/设置类似的内容?在MyClassA和MyClassB中最好带有一个属性。

2 个答案:

答案 0 :(得分:2)

您在两个Autofac常见问题之间徘徊的问题:

可能不是您想要的答案,但是...在这两种情况下,答案是设计中应该解决而不是试图解决的问题迫使这种情况发生。

我们解释了为什么这是一个设计问题on the 'pass a parameter' FAQ。它说“参数”,但您可以读到与“解决接口的特定实现”相同的内容。我将更新/调整文本,使其适用于此处:

  

从技术上讲,您正在解决IFoo-一种不需要了解IBaz实现的组件。 IFoo的实现可以更改,甚至可以更改IBar的实现。您可以注册存根进行测试,也可以切换工作方式,从而无需实施约束。

     

通过假设您“知道”整个依赖链的方式,将IBaz与所需的特定IFoo的实现联系强制打破了基于接口的开发和控制反转给您带来的分离。正在解决。

这基本上也是'implementation by context' FAQ上的注释。在那个答案中,有一个完整的类比,使用面向对象的“动物”层次结构以一种具体的方式来说明为什么它不好。我不会在这里重新粘贴。但是,我要重申,以不同方式对待这两个IBaz实现会破坏Liskov substitution principle-您应该能够交换IBaz实现而不会造成麻烦。 “知道”一个与另一个实质上不同自然意味着它们不相同,因此不应实现相同的接口。 (也许是一个常见的 base 接口,但是当使用它们时,如果不能将基础实现视为相同,那么使用的接口就不会相同。)

我建议您重新设计接口,以免出现此问题。如果这不可能...那么,坦白地说,than the answer you already posted并没有更好的解决方案。这不容易实现,因为通常不应该尝试完成。

再次,很抱歉,这可能不是您想要的答案,但我认为这是答案。

答案 1 :(得分:0)

好吧,这可以解决问题。

        builder.RegisterType<MyClass1>()
            .WithParameter(
                (pi, ctx) => pi.Name == "foo",
                (pfoo, cfoo) => cfoo.Resolve<IFoo>(new ResolvedParameter(
                    (pbar, cbar) => pbar.Name == "bar",
                    (pbar, cbar) => cbar.Resolve<IBar>(new ResolvedParameter(
                        (pbaz, cbaz) => pbaz.Name == "baz",
                        (pbaz, cbaz) => cbaz.ResolveKeyed<IBaz>("1"))))))
            .AsSelf();

        builder.RegisterType<MyClass2>()
            .WithParameter(
                (pi, ctx) => pi.Name == "foo",
                (pfoo, cfoo) => cfoo.Resolve<IFoo>(new ResolvedParameter(
                    (pbar, cbar) => pbar.Name == "bar",
                    (pbar, cbar) => cbar.Resolve<IBar>(new ResolvedParameter(
                        (pbaz, cbaz) => pbaz.Name == "baz",
                        (pbaz, cbaz) => cbaz.ResolveKeyed<IBaz>("2"))))))
            .AsSelf();

但是,我不认为这是做这样的事情的首选方式。