如何使用IOC容器

时间:2015-12-17 18:58:08

标签: c# dependency-injection inversion-of-control ioc-container structuremap

我相信我对依赖注入的理解已经足够了,但是我无法理解IOC容器与服务位置,以及如何利用容器构建我的对象。

假设:

public interface IFooService
{
    void DoSomethingFooey();
}
public class FooService : IFooService
{
    readonly IBarService _barService;

    public FooService(IBarService barService)
    {
        this._barService = barService;
    }

    public void DoSomethingFooey()
    {
        // some stuff
        _barService.DoSomethingBarey();
    }
}


public interface IBarService
{
    void DoSomethingBarey();
}
public class BarService : IBarService
{
    readonly IBazService _bazService;

    public BarService(IBazService bazService)
    {
        this._bazService = bazService;
    }

    public void DoSomethingBarey()
    {
        // Some more stuff before doing ->
        _bazService.DoSomethingBazey();
    }
}


public interface IBazService
{
    void DoSomethingBazey();
}
public class BazService : IBazService
{
    public void DoSomethingBazey()
    {
        Console.WriteLine("Blah blah");
    }
}

如果没有IOC容器,我必须提供构造中的所有依赖项,如下所示:

    public void DoStuff()
    {
        // Without a container, I would have to do something yucky like:
        FooService fs = new FooService(
            new BarService(
                new BazService()
            )
        );

        // or
        BazService bazService = new BazService();
        BarService barService = new BarService(bazService);
        FooService fooService = new FooService(barService);
    }

通过以这种DI方式构建我的课程,我似乎获得了很多,因为我现在可以独立地测试我的课程,在使用DI之前我真的不能。

但是我正在阅读关于做DI的“正确方法”,我会使用像Unity或StructureMap这样的IOC容器......但是我还没有找到我需要了解的如何开始。

我将假设我的容器看起来像这样:

var container = new Container(_ =>
{
    _.For<IFooService>().Use<FooService>();
    _.For<IBarService>().Use<BarService>();
    _.For<IBazService>().Use<BazService>();
});

这取自http://structuremap.github.io/quickstart/

的示例

基于上面的例子,我不确定包含var container...的方法的签名是什么样的,或者如何调用它并保持在范围内。或许更重要的是如何利用容器实际构建对象。

如果我想创建DoStuff()的实例(并依次为FooServiceBarService),我的BazSerivce现在是什么样的?

以前是:

public void DoStuff()
{
    // Without a container, I would have to do something yucky like:
    FooService fs = new FooService(
        new BarService(
            new BazService()
        )
    );

    // or...
}

但现在使用我的容器看起来像什么?我的方法如何知道在哪里寻找我的容器?

希望我有点走上正轨,但如果我不是,请告诉我,以及我缺少的东西。

2 个答案:

答案 0 :(得分:2)

修改为使用容器的DoStuff方法看起来像这样:

public void DoStuff()
{
    IFooService fooService = container.GetInstance<IFooService>();

    // do something with fooService
}

我基于您引用的StructureMap链接。其他IoC容器命名为等效的&#34; GetInstance&#34;方法不同。

您通常不会在尝试获取container实例的同一方法中创建IFooService。通常,您可以在某些初始化方法中将容器配置在其他位置,并将容器保存在您可以轻松访问的位置,例如静态属性。所以,你的DoStuff方法看起来可能更像这样:

public void DoStuff()
{
    IFooService fooService = MyIoCContainer.Current.Getinstance<IFooService>();

    // do something with fooService
}

其中MyIoCContainer只是您已定义的类,其Current属性是您在初始化期间配置的StructureMap容器​​。

但是,您并不总是需要编写这样的代码才能获得服务。一些框架提供了使用IoC容器的钩子,以便您继续在类中使用依赖注入,并且框架负责使用您的IoC容器实例化类。

仅举一个例子,ASP.NET MVC框架提供了一个IDependencyResolver接口和DependencyResolver类,您可以使用该类在Web应用程序中实例化控制器类时允许该框架使用您的IoC容器。这样,您可以继续在控制器中使用依赖注入,因此根本不需要在控制器中明确引用您的IoC容器。有关如何完成的信息,请参见this section on "Including a Custom Dependency Resolver"

因此,理想情况下,您的DoStuff方法及其包含的类看起来像这样,这只是依赖注入的进一步延续。接下来的问题是这个MyStuffDoer类是如何实例化的:要么通过一个了解如何使用IoC容器来创建它的框架,要么是通过在某处创建一些显式代码来从IoC容器中实例化它。

class MyStuffDoer
{
    IFooService fooService;

    public MyStuffDoer(IFooService fooService)
    {
        this.fooService = fooService;
    }

    public void DoStuff()
    {
        // do something with fooService
    }
}

答案 1 :(得分:-1)

我通常这样做是为了保持DI并避免IOC容器的缺点:

/log-in