我相信我对依赖注入的理解已经足够了,但是我无法理解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()
的实例(并依次为FooService
和BarService
),我的BazSerivce
现在是什么样的?
以前是:
public void DoStuff()
{
// Without a container, I would have to do something yucky like:
FooService fs = new FooService(
new BarService(
new BazService()
)
);
// or...
}
但现在使用我的容器看起来像什么?我的方法如何知道在哪里寻找我的容器?
希望我有点走上正轨,但如果我不是,请告诉我,以及我缺少的东西。
答案 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