[英]Using the new operator to create objects/dependencies vs. using DI containers
通过构造函数注入手动连接依赖项有什么不好的地方,而使用DI容器( container.Resolve<T>()
)有什么不好的地方呢?
我的意思是,除了事实之外,每次需要创建依赖对象并将其提供所有依赖项时,您都必须键入一些按键。
实际上,拥有像DI容器这样的中央注册表可以使您更加困惑,并且无法控制您。
我有一个问题和另一个问题(以下),有一段时间了,但是我猜Mark Seemann的文章“ Service Locator”是一个反模式 ,我终于在这里输入了这个问题。
所以,我的另一个问题是:
如果有一个依赖项本身需要一些动态的(例如用户提供的)输入来构造它,该怎么办? 像这样说:
class Dependency : IDependency
{
public Dependency(string userInput) { }
}
class Dependent
{
IDependency _dependency;
void DoSomething()
{
var container = new MyFavoriteContainerFromTheMarket();
Console.Write("Hey, user. How are you feeling?");
var userInput = Console.ReadLine();
// Do DI containers have overloads for Resolve instead of for Register
// that accept parameters to be passed to constructors?
// In other words, what if I don't know the constructor parameter
// value at the time of registration of the dependency but only
// get to know it just before I have to resolve/instantiate the
// dependency? Do popular DI containers of today have overloads
// for that? I assume they must
_dependency = container.Resolve<IDependency>(userInput);
}
}
总的来说,难道不觉得DI Containers会失去您的控制权吗? 在某些情况下手动连接依赖关系不是很好吗?
当然,我知道有时候这很容易,并且可以节省您的键入时间,并且可以创建一个更简洁,更简洁的代码段,但是将它们混合在一起-某些依赖项由容器管理,而有些则由您自己手动提供-所有这些都使它变得混乱,并迫使您记住哪一个是哪个,从而使维护更加困难,您是否同意?
更新资料
等一下。 我只是意识到我的整个例子很复杂。 我本打算在main()中从客户端代码调用Resolve。 我最初应该在这个问题上发布的代码应该是这样的:
class Dependency : IDependency
{
public Dependency(string userInput) { }
}
class Dependent
{
IDependency _dependency;
public Dependent(IDependency dependency)
{
_dependency = dependency;
}
public void DoSomething()
{
}
}
class Program
{
public static void Main(string[] args)
{
var container = new MyFavoriteContainerFromTheMarket();
container.Register<IDependency>(new Dependency(/* I want this to come later */));
container.Register<Dependent>(new Dependent(),
new ConstructorInjection<IDependency>());
Console.Write("Hey, user. How are you feeling?");
var userInput = Console.ReadLine();
// It appears I can't do this as it makes perfect sense
// to have the whole tree of dependencies known at the time
// of registration.
var dependent = container.Resolve<Dependent>(userInput);
dependent.DoSomething();
}
}
我不知道该更新对先前的讨论有何影响。 好像有些白痴(我)在问之前没有想过这个问题。 问这个问题本身就得出了正确的答案,@ Maarten确认了这个答案,并正在尝试帮助我。
抱歉,@ Maarten。 我浪费了你的时间。 :-)
您不应尝试通过调用容器来解析实例。 您应该使用构造函数注入来注入依赖项。 马克·西曼(Mark Seeman)将此称为“不叫容器,让它叫你” 。
要解决创建带有运行时值的注入类型实例的问题,请使用abstract factory 。
因此,您的示例可以这样解决:
class Dependency : IDependency
{
public Dependency(string userInput) { }
}
interface IDependencyFactory {
IDependency Create(string userInput);
}
class DependencyFactory: IDependencyFactory {
IDependency Create(string userInput) {
return new Dependency(userInput);
}
}
class Dependent {
public Dependent(IDependencyFactory factory) {
// guard clause omitted
_factory = factory
}
private readonly IDependencyFactory _factory;
void DoSomething() {
// Do not call the container, let it call you.
// So no container usage here.
//var container = ...
Console.Write("Hey, user. How are you feeling?");
var userInput = Console.ReadLine();
var dependency = _factory.Create(userInput);
// There you go!
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.