没有服务定位器的 IOC

IOC without Service Locator

假设我有 3 个 类、ProgramA(具有依赖项 D1D2)和 B(具有依赖项D3D4)。 Program 在创建 A.

的实例之前初始化一个 IOC 容器并注册一堆类型
class Program
{
    static void Main(string[] args)
    {
        IOC ioc = new IOC();
        //register types

        A a = ioc.Resolve<A>();
    }
}

稍后,a 需要创建 B 的实例,将其两个依赖项注入构造函数。

问题:a应该如何解决B的依赖?我被引导相信传递 IOC 容器,即将它注入 A 是服务定位器模式,这是不好的。如果 B 创建了 C 及其依赖项, B 也需要注入容器,并且容器会在我的代码中乱七八糟。这听起来像是一场测试噩梦。使用全局静态听起来并没有好多少。

理想情况下,您永远不应将容器注入 classes 只是为了解决依赖关系。相反,你在单独的地方注册实例可能是你的启动 class 在运行时应用程序应该能够从容器中注册的实例自动解决依赖关系。

查看以下示例 IOC 容器通常如何注册其实例

注册

SimpleIoc.Default.Register< IDataService, DataService >(); SimpleIoc.Default.Register< MainViewModel >();
SimpleIoc.Default.Register< SecondViewModel >();

解决

SimpleIoc.Default.GetInstance< MainViewModel >();

其实很简单。如果 A 需要 B,它应该接受 B 作为构造函数参数:

public class A
{
    private readonly D1 d1;
    private readonly D2 d2;
    private readonly B b;

    public A(D1 d1, D2 d2, B b) {
        this.d1 = d1;
        this.d2 = d2;
        this.b = b;
    }
}

public class B
{
    private readonly D3 d3;
    private readonly D4 d4;
    private readonly C c;

    public B(D3 d3, D4 d4, C c) {
        this.d3 = d3;
        this.d4 = d4;
        this.c = c;
    }
}

通过这种方式递归地构建对象图,您可以获得非常深的对象图,这完全没问题。这样你只需要应用程序启动路径中的容器(a.k.a。组合根)。

是否 A 需要 B 'later on',或者只是有时,或者几乎从不,这无关紧要。构建对象图应该很快,因此是否不必要地创建 B 应该不是问题。

At some point later on, A needs to create an instance of 'B', injecting its two dependencies into the constructor.

在这种情况下,A 必须依赖于可以为其创建 BBFactory