C# 如何使用IOC容器构造对象
我相信我已经对依赖注入有了足够的了解,可以开始使用它了,但是我在理解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() {
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容器的方法,这样您就不必编写代码了。