C# 如何使用IOC容器构造对象

C# 如何使用IOC容器构造对象,c#,dependency-injection,inversion-of-control,ioc-container,structuremap,C#,Dependency Injection,Inversion Of Control,Ioc Container,Structuremap,我相信我已经对依赖注入有了足够的了解,可以开始使用它了,但是我在理解IOC容器与服务位置以及如何利用容器构造对象方面遇到了困难 class MyStuffDoer { IFooService fooService; public MyStuffDoer(IFooService fooService) { this.fooService = fooService; } public void DoStuff() {

我相信我已经对依赖注入有了足够的了解,可以开始使用它了,但是我在理解IOC容器与服务位置以及如何利用容器构造对象方面遇到了困难

class MyStuffDoer
{
    IFooService fooService;

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

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

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“正确方式”的内容,我会使用一个IOC容器,比如Unity或StructureMap。。。但我还没有找到我需要了解的东西,如何开始

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

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

    // do something with fooService
}
public void DoStuff()
{
    IFooService fooService = MyIoCContainer.Current.Getinstance<IFooService>();

    // do something with fooService
}
但是现在使用我的容器是什么样子的呢?我的方法如何知道在哪里查找容器


希望我在某种程度上是正确的,但是如果我没有,请告诉我,以及我遗漏了什么。

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

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

    public FooService() : this(new 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() : this(new 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");
    }
}

为使用容器而修改的DoStuff方法如下所示:

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

    // do something with fooService
}
public void DoStuff()
{
    IFooService fooService = MyIoCContainer.Current.Getinstance<IFooService>();

    // do something with fooService
}
其中,
MyIoCContainer
只是您定义的一个类,其
Current
属性是您在初始化期间配置的StructureMap容器

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

class MyStuffDoer
{
    IFooService fooService;

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

    public void DoStuff()
    {
        // do something with fooService
    }
}
仅举一个例子,ASP.NET MVC框架提供了一个
IDependencyResolver
接口和
DependencyResolver
类,您可以使用该类在web应用程序中实例化控制器类时允许该框架使用IoC容器。这样,您就可以一直使用依赖项注入到控制器中,因此根本不需要在控制器中显式引用IoC容器。看看这是如何实现的

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

class MyStuffDoer
{
    IFooService fooService;

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

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

将默认构造函数注入到重载构造函数中是一种不好的做法,因为这会导致组件之间的强耦合(违反依赖项反转原则),并降低组件的可重用性,并且很难应用横切关注点(使用装饰器或拦截)不必在整个代码库中进行彻底的更改。此外,我永远无法获得100%的覆盖率(不需要100%的覆盖率),因为无参数构造函数通过接口的具体实现更新类。我无法测试无参数构造函数,因为它可能会对实际应用程序数据产生一些影响。您缺少的是的概念。不要被那些说使用IOC容器是“进行DI的正确方法”的人所愚弄。你可以使用容器,也可以练习。两者都有其价值和起伏。提问总是好的。@Steven我现在通过更新对象所做的事情会被认为是“纯DI”吗?或者这也需要一个合成根?这些文章虽然内容丰富,但仍然相当抽象,至少对我来说,我想得到一些更具体的东西。使用纯DI,您可以在合成根目录中构建对象图。谢谢,但是您提供的DoStuff()与服务定位器模式有何不同?以这种方式进行解析是否会将我的类(以及将使用该容器的所有其他类)与我的IOC容器相耦合?@Kritner我提供的使用IOC容器的
GetInstance
方法的简单示例与服务定位器模式并没有什么不同。我更新了我的答案,讨论了这样一个事实:一些框架可能提供了利用IoC容器的方法,这样您就不必编写代码了。