C#/ Unity中的构造函数注入?

JP *_*son 16 c# dependency-injection unity-container constructor-injection

我正在使用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");
Run Code Online (Sandbox Code Playgroud)

当我在Bus上调用resolve方法时,如何确保注入名为'timmy'的Person'onon'并在解析Train时如何确定具有当时名称'joe'的Person'add'得到解决?

我想也许可以使用命名实例?但我不知所措.任何帮助,将不胜感激.

顺便说一句,我宁愿不创建一个IPerson接口.

Mar*_*ann 34

除非您分别将"joe"和"timmy"注册为命名依赖项,否则您无法确定将"timmy"注入Schoolbus.实际上,如果您尝试将同一个类的两个实例注册为未命名的依赖项,则您将具有不明确的设置,并且您根本无法解析Person.

一般来说,如果你必须注册很多命名实例,你可能会以错误的方式进行DI.DI的主要思想是解析域服务而不是域对象.

DI的主要思想是提供一种机制,允许您将抽象类型(接口或抽象类)解析为具体类型.你的例子没有抽象类型,所以它没有多大意义.

  • 这很公平 - 你可能想读我的书,然后:) (2认同)
  • JP,看看他的书.我发现它非常有见地. (2认同)

Dan*_*ger 19

解决此问题的一种方法是使用具有命名注册的注入构造函数.

// 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
Run Code Online (Sandbox Code Playgroud)

  • 怎么可能将这些存储在配置文件中而不是硬编码? (2认同)

Dav*_*len 14

马克·西曼说得对.我同情你的困惑.当我学会使用自动依赖注入容器时,我自己完成了它.问题是有许多有效和合理的方法来设计和使用对象.然而,只有其中一些方法适用于自动依赖性注入容器.

我的个人历史:在我学会如何使用Inversion of Control容器(如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();
     }
}
Run Code Online (Sandbox Code Playgroud)

在这个设计中,我的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.Save(1234);
     }
}
Run Code Online (Sandbox Code Playgroud)

似乎两个Foo类都是有效的设计.但第二种方法可用于自动依赖注入,而第一种方法则不然.

  • 第二个Main()方法不应该更像:Foo foo = new Foo(new Service()); foo.Save(1234); ? (4认同)