How to implement Dependency Injection in C#?

 In Dot Net
0
252 Views

Problem Scenario

Objects can be loosely or tightly coupled. Tightly coupled objects have dependencies on concrete objects due to which they have lower reusability, maintainability, and testability. Tightly coupled object provide lesser dynamicity due to which user need to change the implementation of class and it’s member functions. We can achieve this via Dependency Injection.

What Dependency Injection do? 

Irrelevant dependencies increase code complexity which results in increased loading and execution time of application. Dependency Injection (DI) is a solution design which provides development of the loosely coupled code. ‘Loose Coupling‘ means the object will only have those dependencies which are required to do their work. Loosely coupled code increases the modularity of application which offers us greater reusability, maintainability, and testability. 

Note: For more details on loosely coupled coding guidelines, please follow Dependency Inversion Principle.

Types of Dependency Injection

1. Constructor Injection:  It uses parameters to inject dependencies. The object has no defaults or single constructor due to which specified values are required at the time of creation to instantiate the object. This is the most common type of DI. We can use injected component anywhere in the class. It makes a strong dependency contract. In this type, we can make dependency immutable in order to prevent it from circular dependency. For entire dependency graph, it requires up-front wiring which needs a public constructor in the class to pass dependency as a parameter.

Example

Consider a scenario, where a student took admission in school and school provides bag, dress, books etc to that student. Here, the student does not like to receive goodies from different counters. What the student would like, that he/she should receive all the goodies from a single counter in one go.

Create a console application of any name and create two classes.

Dependency Injection

In above image, SchoolBag and SchoolDress are the basic ‘Service classes’ having  Bag and  Dress methods respectively.

In the image below, Student class is ‘Client class’ using the service (i.e. SchoolBag ) and assigning that bag to ‘John’ in the main program.

Dependency Injection

The Student constructor is assigning a new instance of SchoolBag class. And the Assign method is acting like a Service_Start() method. It is receiving the studentName from the main program and passing it to Bag method of SchoolBag class.

Output

The output of above implementation will be,

Dependency Injection

Above implementation has one issue i.e. we only managed to assign SchoolBag to the Student . SchoolDress is still left or what if we want to provide some other things to the student. Since the object of SchoolBag is created inside the Student class’s constructor, we have to modify the implementation of Student class for SchoolDress and the for some other thing, which is not a proper implementation. This is a type of concrete dependency. To avoid this, we can use interfaces to provide a level of indirection. See the below implementation.

Implementing Interface

Create a service interface.

interface IThings 
  { 
      void Assign(string studentName); 
  }

and now remove the previous implementation of the service classes (i.e. SchoolBag and SchoolDress ) and implement the above service interface in the service classes. Like this,

Dependency Injection

After this, we need to alter our client class. We need to “inject” a parameter of service interface type (i.e. IThings ) in the constructor of Student class.

Dependency Injection

In above image, we have injected a new object into the client class. And we can use this object anywhere in the client class. Below is the respective output.

Dependency Injection

Source Code

Below is the full source code.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
namespace DependencyInjection 
{ 
    interface IThings 
    { 
        void Assign(string studentName); 
    } 
  
    class SchoolBag : IThings 
    { 
        public void Assign(string studentName) 
        { 
            Console.WriteLine("{0} recieved Bag", studentName); 
        } 
    } 
  
    class SchoolDress : IThings 
    { 
        public void Assign(string studentName) 
        { 
            Console.WriteLine("{0} recieved Dress", studentName); 
        } 
    } 
  
    class Student 
    { 
        private IThings thing; 
        public Student(IThings iThing) 
        { 
            thing = iThing; 
        } 
        public void Recieve(string studentName) 
        { 
            thing.Assign(studentName); 
        } 
    } 
  
    class Program 
    { 
        static void Main(string[] args) 
        { 
            Student obj1 = new Student(new SchoolBag()); 
            obj1.Recieve("John"); 
  
            Student obj2 = new Student(new SchoolDress()); 
            obj2.Recieve("John"); 
  
            Console.ReadLine(); 
        } 
    } 
}

2. Setter or Property Injection: In this, we don’t require to change the constructor. We pass dependencies through the exposed public properties. In this, we can create costly resources or services as late as possible and only when required.  It is difficult to identify which dependencies are required and it is beneficial to perform null checks in setter properties. For entire dependency graph, it does not require up-front wiring.

In addition to our previous code, the implementation we did for Student constructor has now been transferred to the setter of SetStudent property. And the new object which was previously passed as a parameter in the constructor of Student class, has now been assigned to the  SetStudent property in the main program. The output will be same as it was for constructor injection. See the following image.

 

Dependency Injection

3. Method Injection: In this, the dependency is been injected within a single method to be used by that method only. It is useful in case when only one method needs dependency, not the whole class.

In addition to our previous code, the implementation we did for setter property has now been transferred to the Assign method and the dependency has been injected as a parameter from main program. The output will be same as it was for property injection. See the following image.

 

Dependency Injection

Conclusion

With DI, you can inject extra code between the conditions. To illustration, you can utilize the Constructor Injection to give an instance its conditions. In the event that you have a class with ten functions that have no dependencies. Then, you have to include one or more than one function with a dependency. You can change the constructor to utilize Constructor Injection.

Then again, you can basically include another constructor that takes the dependency as a parameter. However, in the event that there is a dependency which is costly to make, you can utilize the Setter Injection. It gives you a chance to make the expensive resources only when required. As should be obvious, DI makes code testable, viable, reusable and coherent.

Recommended Posts

Start typing and press Enter to search