Explain dependency injection in C#

CsharpServer Side ProgrammingProgramming

A dependency is an object that another object depends on. Dependency Injection (or inversion) is basically providing the objects that an object needs, instead of having it construct the objects themselves. It is a useful technique that makes testing easier, as it allows you to mock the dependencies.

For example, if class A calls a method on class B, which in turn calls a method on class C, that means A depends on B and B depends on C. Using dependency injection, we can pass an instance of class C to class B, and pass an instance of B to class A, instead of having these classes to construct the instances of B and C.

In the example, below, class Runner has a dependency on the class Logger. Notice that in the class Runner creates an instance of Logger in the constructor. There are a few problems with this code.

  • This ties the logger class to Runner and we can't substitute it with other classes, without modifying Runner.

  • If Logger has any dependencies, then Worker has to configure them before instantiating Logger.

  • Testing is harder. If Logger is a resource-intensive class, such as accessing the network or file system, it will slow the testing down. We can't replace it easily.

using System;
class Program{
   static void Main(string[] args){
      var runner = new Runner();
      runner.Run();
   }
}
class Runner{
   private Logger _logger;
   public Runner(){
      _logger = new Logger();
   }
   public void Run(){
      // Do some work
      _logger.Log("Message to be logged");
   }
}
class Logger{
   public void Log(string message){
      Console.WriteLine(message);
   }
}

Using dependency injection, we modify the constructor of Runner to accept an interface ILogger, instead of a concrete object. We change the Logger class to implement ILogger. This allows us to pass an instance of the Logger class to the Runner's constructor. The benefit of this is that during testing, we can create a TestLogger class that implements ILogger and pass that to Runner's constructor.

Example

 Live Demo

using System;
class Program{
   static void Main(string[] args){
      var logger = new Logger();
      var runner = new Runner(logger);
      runner.Run();
   }
}
class Runner{
   private ILogger _logger;
   public Runner(ILogger logger){
      _logger = logger;
   }
   public void Run(){
      // Do some work
      _logger.Log("Message to be logged");
   }
}
interface ILogger{
   void Log(string message);
}
class Logger : ILogger{
   public void Log(string message){
      Console.WriteLine(message);
   }
}

Output

Message to be logged
raja
Published on 19-May-2021 08:18:30
Advertisements