我听到很多人说使用IoC.Resolve()是一种不好的做法,但我从来没有听说过一个很好的理由(如果它只是关于测试而不是你可以嘲笑容器,那么你就是完成)。
现在使用Resolve而不是Constructor Injection的优点是您不需要创建 在构造函数中有5个参数的类,以及每当你要创建的实例时 那个课你不需要提供任何东西
答案 0 :(得分:49)
IoC.Resolve<>
是Service Locator模式的一个示例。该模式强加了一些构造函数注入没有的限制:
在我看来,这些限制将服务定位器模式置于大球和依赖注入之间的中间位置:如果必须使用它,则非常有用,但到目前为止并非最佳选择。
答案 1 :(得分:26)
如果您创建具有5个依赖项的类,则会遇到IoC.Resolve以外的问题。
拉动依赖项(而不是通过构造函数推送它们)完全忽略了使用IoC框架的重点。您想要反转依赖项。没有你的课程依赖于IoC框架,但反过来。
如果您在某些情况下不需要所有依赖项,那么您可能应该拆分您的类,或者通过使它们成为属性依赖项来使某些依赖项成为可选项。
您的课程取决于容器。除非你提供一个,否则它们将无法工作。无论是真的还是假的都无所谓。它们通过静态依赖性固有地绑定到容器。这会给你额外的工作带来任何你的课程。任何时候你想使用你的类,你需要用它们拖动容器。没有好处!服务定位器只是一切的全局包,这可能违背了面向对象编程的所有原则。
答案 2 :(得分:7)
Ioc.Resolve本质上是服务定位器模式。它有它的位置,但并不理想。从体系结构的角度来看,构造函数注入是首选,因为依赖关系更明确,而SL隐藏了类中的依赖关系。这降低了可测试性,并使该过程变得更加复杂。
如果可以的话,我建议你阅读my recent series关于减少代码耦合的技术,包括SL,DI和IoC。
答案 3 :(得分:3)
一个优点是,使用构造函数注入时,所有类依赖项都是预先可见的。
使用.Resolve
,您必须阅读代码才能确定依赖关系。
答案 4 :(得分:1)
我必须指出跳过构造函数注入并使用静态注入并不一定是邪恶的。这有很好的应用,最具体的例子是在工厂模式实现中使用它。
public static class ValidationFactory
{
public static Result Validate<T>(T obj)
{
try
{
var validator = ObjectFactory.GetInstance<IValidator<T>>();
return validator.Validate(obj);
}
catch (Exception ex)
{
var result = ex.ToResult();
...
return result;
}
}
}
我在StructureMap中使用它来处理我的验证层。
编辑:我直接使用容器的另一个例子是让你的一些域对象成为单例,而不是让它们成为静态类,并引入静态类所做的所有诡计。
在我的一些观点中,我连接了一些像这样的实体。通常我会给一个带有Description属性的Enum给我3个值选择但是在这种情况下第3个也需要是一个字符串而不是int所以我创建了一个包含这3个属性的接口并继承了所有的域对象它。然后我让我的容器扫描我的程序集并自动注册所有这些然后将它们拉出来我只有
SomeObject ISomeView.GetMyObject
{
get { return new SomeObject { EmpoweredEnumType =
ObjectFactory.GetNamedInstance<IEmpEnum>("TheObjectName");
}
}
答案 5 :(得分:1)
由于这个问题值得商榷,我不会说&#34;使用这个或那个&#34;
看起来使用Service Locator并不是一件好事,如果你可以依赖它(我们通常会在某些DI框架上做)。使用DI,我们可以轻松地更改框架,使用Service Locator,我们可以创建与框架的SL部分的耦合。
关于Bryan Watts的回答,当你稍后阅读时 Service Locator vs Dependency Injection
...使用[constructor]注入没有显式请求,服务出现在应用程序类中 - 因此控制反转。
控制反转是框架的一个共同特征,但它需要付出代价。当您尝试调试时,它往往很难理解并导致问题。 总的来说,除非我需要,否则我宁愿避免它。这并不是说它是一件坏事,只是因为我觉得它需要通过更直接的方式证明自己是正确的。替代品。
然后,如果你稍后阅读是实际使用构造函数注入的另一个理由(控制反转)。
我的观点是,在小型项目中使用SL是可以的,因为主要的不是在我们的自定义开发类之间建立耦合。
使用StructureMap exmaple这应该是可以接受的:
public class Demo
{
private ISomething something = ObjectFactory.GetInstance<ISomething>();
private IFoo foo = ObjectFactory.GetInstance<IFoo>();
}
是的,代码取决于SM Frx,但是你多久更换一次DI Frx?
对于单元测试,可以设置模拟
public class SomeTestClass
{
public SomeTest()
{
ObjectFactory.Inject<ISomething>(SomeMockGoesHere);
ObjectFactory.Inject<IFoo>(SomeMockGoesHere);
Demo demo = new Demo() //will use mocks now
}
}
使用Resolve而不是Constructor Injection的优点是您不需要在构造函数中创建具有5个参数的类
但最终可能会制造更多&#34;管道&#34;用于单元测试。
答案 6 :(得分:0)
我想说这是一个疯狂的参数注入量。
争取一个参数,最多可能是2个,这几乎是所有场景,当然应该是一个接口。除此之外,我闻到一只老鼠(设计缺陷)。
答案 7 :(得分:0)
您不需要在构造函数中创建具有5个参数的类,并且每当您要创建该类的实例时,您都不需要为其提供任何内容
几点:
即使您没有通过类的API(在这种情况下是构造函数),也会存在依赖关系。但是,理解并测试试图隐藏其依赖关系的类会更加困难。