Condividi tramite


Annotating Objects for Constructor Injection

patterns & practices Developer Center

Download codeDownload PDFOrder Paperback

Unity supports automatic dependency injection for class constructors. You can use the Unity container to generate instances of dependent objects and wire up the target class with these instances. This topic explains how to use both the automatic constructor injection mechanism and an attribute applied to the constructor of a class to define the dependency injection requirements of that class. The attribute can also specify parameters that the constructor will pass to the dependent object that the container generates.

To perform injection of dependent classes into objects you create through the Unity container, you can use the following techniques:

  • Single Constructor Automatic Injection. With this technique, you allow the Unity container to satisfy any constructor dependencies defined in parameters of the constructor automatically. You use this technique when there is a single constructor in the target class.
  • Specifying Named Type Mappings. With this technique, you specify named mappings for dependencies in the parameters of a class constructor. Named mappings allow you to specify more than one mapping for an interface or base class, or for a type registration.
  • Multiple Constructor Injection Using an Attribute. With this technique, you apply attributes to the class constructor(s) that specify the dependencies. You use this technique when there is more than one constructor in the target class.

Constructor injection is a form of mandatory injection of dependent objects, as long as developers use the Unity container to generate the target object. The dependent object instance is generated when the Unity container creates an instance of the target class using the constructor. For more information, see Notes on Using Constructor Injection.

Single Constructor Automatic Injection

For automatic constructor injection, you simply specify as parameters of the constructor the dependent object types. You can specify the concrete type, or specify an interface or base class for which the Unity container contains a registered mapping.

To use automatic single-constructor injection to create dependent objects

  1. Define a constructor in the target class that takes as a parameter the concrete type of the dependent class. For example, the following code shows a target class named MyObject containing a constructor that has a dependency on a class named MyDependentClass.

    public class MyObject
    {
      public MyObject(MyDependentClass myInstance)
      { 
        // work with the dependent instance
        myInstance.SomeProperty = "SomeValue";
        // or assign it to a class-level variable
      }
    } 
    
    Public Class MyObject
      Public Sub New(myInstance As MyDependentClass)
        ' work with the dependent instance
        myInstance.SomeProperty = "SomeValue"
        ' or assign it to a class-level variable
      End Sub
    End Class 
    
  2. In your run-time code, use the Resolve method of the container to create an instance of the target class. The Unity container will instantiate the dependent concrete class and inject it into the target class. For example, the following code shows how you can instantiate the example target class named MyObject containing a constructor that has a dependency on a class named MyDependentClass.

    IUnityContainer uContainer = new UnityContainer();
    MyObject myInstance = uContainer.Resolve<MyObject>();
    
    Dim uContainer As IUnityContainer = New UnityContainer()
    Dim myInstance As MyObject = uContainer.Resolve(Of MyObject)()
    
  3. Alternatively, you can define a target class that contains more than one dependency defined in constructor parameters. The Unity container will instantiate and inject an instance of each one. For example, the following code shows a target class named MyObject containing a constructor that has dependencies on two classes named DependentClassA and DependentClassB.

    public class MyObject
    {
      public MyObject(DependentClassA depA, DependentClassB depB)
      { 
        // work with the dependent instances
        depA.SomeClassAProperty = "SomeValue";
        depB.SomeClassBProperty = "AnotherValue";
        // or assign them to class-level variables
      }
    } 
    
    Public Class MyObject
      Public Sub New(depA As DependentClassA, depB As DependentClassB)
        ' work with the dependent instance
        depA.SomeClassAProperty = "SomeValue"
        depB.SomeClassBProperty = "AnotherValue"
        ' or assign them to class-level variables
      End Sub
    End Class 
    
  4. In your run-time code, use the Resolve method of the container to create an instance of the target class. The Unity container will create an instance of each of the dependent concrete classes and inject them into the target class. For example, the following code shows how you can instantiate the example target class named MyObject containing a constructor that has constructor dependencies.

    IUnityContainer uContainer = new UnityContainer();
    MyObject myInstance = uContainer.Resolve<MyObject>();
    
    Dim uContainer As IUnityContainer = New UnityContainer()
    Dim myInstance As MyObject = uContainer.Resolve(Of MyObject)()
    
  5. In addition to using concrete types as parameters of the target object constructor, you can use interfaces or base class types and then register mappings in the Unity container to translate these types into the correct concrete types. Define a constructor in the target class that takes as parameters the interface or base types of the dependent class. For example, the following code shows a target class named MyObject containing a constructor that has a dependency on a class that implements the interface named IMyInterface and a class that inherits from MyBaseClass.

    public class MyObject
    {
      public MyObject(IMyInterface interfaceObj, MyBaseClass baseObj)
      { 
        // work with the concrete dependent instances
        // or assign them to class-level variables
      }
    } 
    
    Public Class MyObject
      Public Sub New(interfaceObj As IMyInterface, baseObj As MyBaseClass)
        ' work with the dependent instance
        ' or assign them to class-level variables
      End Sub
    End Class 
    
  6. In your run-time code, register the mappings you require for the interface and base class types, and then use the Resolve method of the container to create an instance of the target class. The Unity container will instantiate an instance of each of the mapped concrete types for the dependent classes and inject them into the target class. For example, the following code shows how you can instantiate the example target class named MyObject containing a constructor that has a dependency on the two objects of type IMyInterface and MyBaseClass.

    IUnityContainer uContainer = new UnityContainer()
       .RegisterType<IMyInterface, FirstObject>()
       .RegisterType<MyBaseClass, SecondObject>();
    MyObject myInstance = uContainer.Resolve<MyObject>();
    
    Dim uContainer As IUnityContainer = New UnityContainer() _
       .RegisterType(Of IMyInterface, FirstObject)() _
       .RegisterType(Of MyBaseClass, SecondObject)()
    Dim myInstance As MyObject = uContainer.Resolve(Of MyObject)()
    

Specifying Named Type Mappings

The preceding example shows how you can resolve types for constructor parameters using the default (unnamed) mappings in the container. If you register more than one mapping for a type, you must differentiate them by using a name. In this case, you can specify which named mapping the container will use to resolve each constructor parameter type.

To use attributed constructor injection with named container type mappings

  1. Define a constructor in the target class that takes as a parameter the concrete type of the dependent class, and apply a Dependency attribute to the parameter that specifies the name of the registered mapping to use. For example, the following code shows a target class named MyObject containing a constructor that has a dependency on a service registered with the name myDataService, and which implements the IMyService interface. It assumes that the container contains a mapping defined with the name DataService between the IMyService interface and a concrete implementation of this interface.

    public class MyObject
    {
      public MyObject([Dependency("DataService")] IMyService myDataService)
      { 
        // work with the service here
      }
    } 
    
    Public Class MyObject
      Public Sub New(<Dependency("DataService")> myDataService As IMyService)
        ' work with the service here
      End Sub
    End Class 
    
  2. In your run-time code, use the Resolve method of the container to create an instance of the target class. The Unity container will instantiate the dependent concrete class defined in the mapping named DataService and inject it into the target class. For example, the following code shows how you can instantiate the example target class shown above.

    IUnityContainer uContainer = new UnityContainer();
    MyObject myInstance = uContainer.Resolve<MyObject>();
    
    Dim uContainer As IUnityContainer = New UnityContainer()
    Dim myInstance As MyObject = uContainer.Resolve(Of MyObject)()
    

You can use the Dependency attribute on more than one constructor parameter. You can also use it when the constructor defines more than one parameter of the same type to differentiate the mappings and ensure that the appropriate concrete type is returned for each parameter.

Note

If you specify a named mapping and there is no mapping registered for that type and name, the container will raise an exception.

Multiple Constructor Injection Using an Attribute

When a target class contains more than one constructor with the same number of parameters, you must apply the InjectionConstructor attribute to the constructor that the Unity container will use to indicate which constructor the container should use. As with automatic constructor injection, you can specify the constructor parameters as a concrete type, or you can specify an interface or base class for which the Unity container contains a registered mapping.

To use attributed constructor injection when there is more than one constructor

  1. Apply the InjectionConstructor attribute to the constructor in the target class that you want the container to use. In the simplest case, the target constructor takes as a parameter the concrete type of the dependent class. For example, the following code shows a target class named MyObject containing two constructors, one of which has a dependency on a class named MyDependentClass and has the InjectionConstructor attribute applied.

    public class MyObject
    {
    
      public MyObject(SomeOtherClass myObjA)
      { 
        ...
      }
    
      [InjectionConstructor]
      public MyObject(MyDependentClass myObjB)
      { 
        ...
      }
    
    } 
    
    Public Class MyObject
    
      Public Sub New(myObjA As SomeOtherClass)
        ...
      End Sub
    
      <InjectionConstructor()> _
      Public Sub New(myObjB As MyDependentClass)
        ...
      End Sub
    
    End Class 
    
  2. In your run-time code, use the Resolve method of the container to create an instance of the target class. The Unity container will instantiate the dependent concrete class defined in the attributed constructor and inject it into the target class. For example, the following code shows how you can instantiate the example target class named MyObject containing an attributed constructor that has a dependency on a class named MyDependentClass.

    IUnityContainer uContainer = new UnityContainer();
    MyObject myInstance = uContainer.Resolve<MyObject>();
    
    Dim uContainer As IUnityContainer = New UnityContainer()
    Dim myInstance As MyObject = uContainer.Resolve(Of MyObject)()
    
  3. Alternatively, you can define a multiple-constructor target class that contains more than one dependency defined in the target constructor parameters. The Unity container will instantiate and inject an instance of each one. For example, the following code shows a target class named MyObject containing an attributed constructor that has dependencies on two classes, DependentClassA and DependentClassB.

    public class MyObject
    {
    
      public MyObject(SomeClassA objA, SomeClassB objB)
      { 
        ...
      }
    
      [InjectionConstructor]
      public MyObject(DependentClassA depA, DependentClassB depB)
      { 
        ...
      }
    
    } 
    
    Public Class MyObject
    
      Public Sub New(objA As SomeClassA, objB As SomeClassB)
        ...
      End Sub
    
      <InjectionConstructor()> _
      Public Sub New(depA As DependentClassA, depB As DependentClassB)
        ...
      End Sub
    
    End Class 
    
  4. In your run-time code, use the Resolve method of the container to create an instance of the target class. The Unity container will create an instance of each of the dependent concrete classes defined in the attributed constructor and inject them into the target class. For example, the following code shows how you can instantiate the example target class named MyObject containing a constructor that has constructor dependencies

    IUnityContainer uContainer = new UnityContainer();
    MyObject myInstance = uContainer.Resolve<MyObject>();
    
    Dim uContainer As IUnityContainer = New UnityContainer()
    Dim myInstance As MyObject = uContainer.Resolve(Of MyObject)()
    
  5. In addition to using concrete types as parameters of the target object constructor, you can use interfaces or base class types, and then register mappings in the Unity container to translate these types into the correct concrete types. For details, see steps 5 and 6 of the procedure Single Constructor Automatic Injection.

Notes on Using Constructor Injection

The following notes will help you to get the greatest benefit from using constructor injection with Unity.

How Unity Resolves Target Constructors and Parameters

When a target class contains more than one constructor, Unity will use the one that has the InjectionConstructor attribute applied. If there is more than one constructor, and none carries the InjectionConstructor attribute, Unity will use the constructor with the most parameters. If there is more than one constructor that is the "longest" with the same number of parameters, Unity will raise an exception.

Constructor Injection with Existing Objects

If you use configuration or the RegisterInstance method to register an existing object, constructor injection does not take place on that object because it has already been created outside of the influence of the Unity container. Even if you call the BuildUp method of the container and pass it the existing object, constructor injection will never take place because the constructor will not execute.

Instead, you can use property (setter) injection by applying a Dependency attribute to a public property. Alternatively, create an Initialize method for the class that takes the type to resolve as a parameter and apply the InjectionMethod attribute to this method. Unity will resolve the parameter and call the method. Inside the method, you can store a reference to the resolved object for use in your code. For more details, see Annotating Objects for Method Call Injection.

Avoiding Circular References

Dependency injection mechanisms can cause application errors if there are circular references between objects that the container will create. For more details, see Circular References with Dependency Injection.

When to Use Constructor Injection

You should consider using constructor injection in the following situations:

  • When you want to perform dependency injection on new instances of objects or classes created through the Unity container. Constructor injection cannot be used with existing object instances.
  • When you want to instantiate dependent objects automatically when you instantiate the parent object.
  • When you want a simple approach that makes it easy to see in the code what the dependencies are for each class.
  • When the parent object does not require a large number of constructors that forward to each other.
  • When the parent object constructors do not require a large number of parameters.
  • When you want to be able to hide field values from view in the application code by not exposing them as properties or methods.
  • When you want to control which objects are injected by editing the code of the dependent object instead of the parent object or application.

If you are not sure which type of injection to use, the recommendation is that you use constructor injection unless you are working with an existing instance of an object or class.

Note

You can also configure constructor injection at design time or run time. For more information, see Configuring Unity.

Next Topic | Previous Topic | Home | Community