Partager via


Annotating Objects for Constructor Injection

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

The latest Unity Application Block information can be found at the Unity Application Block site.

The Unity Application Block supports automatic dependency injection and dependency injection specified through attributes applied to members of the target class. You can use the Unity container to generate instances of dependent objects and wire up the target class with these instances.

Typical Goals

In this scenario, you 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.

Solution

To perform injection of dependent classes into objects you create through the Unity container, you can use the following two 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.
  • 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, provided 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
      }
    } 
    
    'Usage
    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>();
    
    'Usage
    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
      }
    } 
    
    'Usage
    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>();
    
    'Usage
    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
      }
    } 
    
    'Usage
    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>();
    
    'Usage
    Dim uContainer As IUnityContainer = New UnityContainer() _
       .RegisterType(Of IMyInterface, FirstObject)() _
       .RegisterType(Of MyBaseClass, SecondObject)()
    Dim myInstance As MyObject = uContainer.Resolve(Of MyObject)()
    

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)
      { 
        ...
      }
    
    } 
    
    'Usage
    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>();
    
    'Usage
    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 named DependentClassA and DependentClassB.

    public class MyObject
    {
    
      public MyObject(SomeClassA objA, SomeClassB objB)
      { 
        ...
      }
    
      [InjectionConstructor]
      public MyObject(DependentClassA depA, DependentClassB depB)
      { 
        ...
      }
    
    } 
    
    'Usage
    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>();
    
    'Usage
    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 most benefit from using constructor injection with the Unity Application Block.

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 such constructor (more than one of the "longest" with the same number of parameters), Unity will raise an exception.

Constructor Injection with Existing Objects

If you use 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, mark the constructor parameter containing the object you want to inject with the Dependency attribute to force property injection to take place on that object, and then call the BuildUp method. This is a similar process to property (setter) injection. It ensures that the dependent object can generate any dependent objects it requires. For more details, see Annotating Objects for Property (Setter) 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:

  • You want to instantiate dependent objects automatically when your instantiate the parent object.
  • You want a simple approach that makes it easy to see in the code what the dependencies are for each class.
  • The parent object does not require a large number of constructors that forward to each other.
  • The parent object constructors do not require a large number of parameters.
  • You want to be able to hide field values from view in the application code by not exposing them as properties or methods.
  • 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. This is likely to satisfy almost all general requirements.

Note

You can also apply constructor injection at run time using the configuration API of the Unity container. For more information, see Configuring Containers at Run Time.

More Information

For more information about the techniques discussed in this scenario, see the following topics: