Constructor Injection in C#/Unity?

前端 未结 3 1157
醉梦人生
醉梦人生 2020-12-05 03:21

I\'m using C# with Microsoft\'s Unity framework. I\'m not quite sure how to solve this problem. It probably has something to do with my lack of understanding DI with Unity.<

相关标签:
3条回答
  • 2020-12-05 03:46

    Mark Seeman got it right. And I sympathize with your confusion. I went through it myself when I learned to use automatic dependency injection containers. The problem is that there are many valid and reasonable ways to design and use objects. Yet only some of those approaches work with automatic dependency injectorion containers.

    My personal history: I learned OO principles of object construction and Inversion Of Control long before I learned how to use Inversion of Control containers like the Unity or Castle Windsor containers. I acquired the habit of writing code like this:

    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();
         }
    }
    

    In this design, my Foo class is responsible for saving accounts to the database. It needs an account number to do that and a service to do the dirty work. This is somewhat similar to the concreted classes you provided above, where each object takes some unique values in the constructor. This works fine when you instantiate the objects with your own code. You can pass in the appropriate values at the right time.

    However, when I learned about automatic dependency injection containers, I found that I was no longer instantiating Foo by hand. The container would instantiate the constructor arguments for me. This was a great convenience for the services like IService. But it obviously does not work so well for integers and strings and the like. In those cases, it would provide a default value (like zero for an integer). Instead, I had been accustomed to passing in context-specific values like account number, name, etc... So I had to adjust my style of coding and design to be like this:

    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);
         }
    }
    

    It appears that both Foo classes are valid designs. But the second is useable with automatic dependency injection, and the first is not.

    0 讨论(0)
  • 2020-12-05 04:00

    One way to solve this would be to use an injection constructor with a named registration.

    // 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
    
    0 讨论(0)
  • 2020-12-05 04:02

    Unless you register respectively "joe" and "timmy" as named dependencies, you can't be sure that "timmy" is injected into Schoolbus. In fact, if you attempt to register two instances of the same class as unnamed dependencies, you will have an ambiguous setup, and you will not be able to resolve Person at all.

    In general, if you have to register a lot of named instances you are probably going about DI in the wrong way. The main idea of DI is to resolve Domain Services more than Domain Objects.

    The primary idea of DI is to provide a mechanism that allows you to resolve abstract types (interfaces or abstract classes) into concrete types. Your example has no abstract types, so it doesn't really make a lot of sense.

    0 讨论(0)
提交回复
热议问题