我正在使用 C# 和 Microsoft 的 Unity 框架。我不太确定如何解决这个问题。这可能与我对 Unity 的 DI 缺乏了解有关。
我的问题可以使用以下示例代码来总结:
class Train(Person p) { ... }
class Bus(Person p) { ... }
class Person(string name) { ... }
Person dad = new Person("joe");
Person son = new Person("timmy");
当我在总线上调用解析方法时,如何确定名为“timmy”的人“儿子”被注入,在解析火车时如何确定名为“joe”的人“爸爸”被解析?
我在想也许可以使用命名实例?但我不知所措。任何帮助将不胜感激。
顺便说一句,我宁愿不创建 IPerson 界面。
除非您分别将“joe”和“timmy”注册为命名依赖项,否则您无法确定“timmy”已注入Schoolbus。事实上,如果您尝试将同一类的两个实例注册为未命名依赖项,您将得到一个不明确的设置,并且根本无法解析
Person
。
一般来说,如果您必须注册大量命名实例,那么您可能会以错误的方式进行 DI。 DI 的主要思想是解决域服务而不是域对象。
DI 的主要思想是提供一种机制,允许您将抽象类型(接口或抽象类)解析为具体类型。您的示例没有抽象类型,因此它并没有多大意义。
解决此问题的一种方法是使用具有命名注册的注入构造函数。
// Register timmy this way
Person son = new Person("Timmy");
container.RegisterInstance<Person>("son", son);
// OR register timmy this way
container.RegisterType<Person>("son", new InjectionConstructor("Timmy"));
// Either way, register bus this way.
container.RegisterType<Bus>(new InjectionConstructor(container.Resolve<Person>("son")));
// Repeat for Joe / Train
马克·西曼说得对。我对你的困惑表示同情。当我学习使用自动依赖注入容器时,我自己也经历过。问题是有许多有效且合理的方法来设计和使用对象。然而,只有其中一些方法适用于自动依赖注入容器。
我的个人经历:早在我学习如何使用 Unity 或 Castle Windsor 容器等控制反转容器之前,我就已经了解了对象构造和控制反转的 OO 原理。我养成了这样编写代码的习惯:
public class Foo
{
IService _service;
int _accountNumber;
public Foo(IService service, int accountNumber)
{
_service = service;
_accountNumber = accountNumber;
}
public void SaveAccount()
{
_service.Save(_accountNumber);
}
}
public class Program
{
public static void Main()
{
Foo foo = new Foo(new Service(),1234);
foo.Save();
}
}
在这个设计中,我的 Foo 类负责将帐户保存到数据库。它需要一个帐号来做到这一点,并需要一项服务来完成肮脏的工作。这有点类似于上面提供的具体类,其中每个对象在构造函数中都采用一些唯一的值。当您使用自己的代码实例化对象时,这种方法效果很好。您可以在合适的时间传入合适的值。
但是,当我了解自动依赖注入容器时,我发现我不再手动实例化 Foo。容器将为我实例化构造函数参数。这对于IService这样的服务来说是一个很大的便利。但对于整数和字符串等,它显然不太适用。在这些情况下,它将提供一个默认值(例如整数为零)。相反,我已经习惯了传递特定于上下文的值,例如帐号、姓名等......所以我必须调整我的编码和设计风格,如下所示:
public class Foo
{
IService _service;
public Foo(IService service)
{
_service = service;
}
public void SaveAccount(int accountNumber)
{
_service.Save(accountNumber);
}
}
public class Program
{
public static void Main()
{
Foo foo = new Foo(new Service());
foo.SaveAccount(1234);
}
}
看来两个 Foo 类都是有效的设计。但第二个可以通过自动依赖注入使用,而第一个则不能。