Today, I am going to explain in detail about dependency injection in C#. This article is for those developers who don't know anything about Dependency Injection (DI). Just go through all the examples below along with code comments to get a better understanding of DI.
Let's start,
Before we start DI, let's understand what tightly coupled is in C#. If you are familiar with tightly coupled, then skip this section.
Tightly coupled in C#
Tight coupling is when a group of classes are highly dependent on one another. See the below example which is tightly coupled.
- public class SavingAccount
- {
- public void PrintData()
- {
- Console.WriteLine("Saving account data.");
- }
- }
-
- public class CurrentAccount
- {
- public void PrintData()
- {
- Console.WriteLine("Current account data.");
- }
- }
-
-
-
-
- public class Account
- {
-
-
- SavingAccount savingAccount = new SavingAccount();
-
-
-
- CurrentAccount currentAccount = new CurrentAccount();
-
- public void PrintAccounts()
- {
- savingAccount.PrintData();
- currentAccount.PrintData();
- }
- }
-
- public class Program
- {
- static void Main(string[] args)
- {
- Account account = new Account();
- account.PrintAccounts();
- Console.ReadLine();
- }
- }
The account class is tightly coupled as every time, we need to create the instance of both SavingAccount and CurrentAccount class to call the PrintData() method of each. So it is highly dependent on either SavingAccount or CurrentAccount class.
Now the question is, how to avoid this tightly coupled state? The answer is by using Dependency injection. DI is achieved using interfaces.
What is Dependency Injection in C#?
Dependency Injection (DI) is a software pattern. DI is a technique whereby one object supplies the dependencies of another object. With the help of DI, we can write loosely coupled code. A loosely-coupled code is a code where all your classes can work independently without relying on each other. There are four types of DI in C#
- Constructor Injection
- Setter or property Injection
- Method Injection
- Service Locator Injection
I am not discussing the "Service Locator Injection". Let us understand constructor, setter or property, and method injection with an example.
DI using Constructor Injection
Constructor injection is nothing but the process of injecting dependent class object through the constructor. What is meant by this?
In the above example, the account class has a dependency on SavingAccount & CurrentAccount classes. So constructor injection means, injecting SavingAccount & CurrentAccount class objects in Account class constructor using interface. Let us see how we can do this.
-
- public interface IAccount
- {
- void PrintData();
- }
-
-
- public class SavingAccount : IAccount
- {
- public void PrintData()
- {
- Console.WriteLine("Saving account data.");
- }
- }
-
-
- public class CurrentAccount : IAccount
- {
- public void PrintData()
- {
- Console.WriteLine("Current account data.");
- }
- }
-
-
-
- public class Account
- {
- private IAccount account;
-
-
- public Account(IAccount account)
- {
- this.account = account;
- }
-
- public void PrintAccounts()
- {
- account.PrintData();
- }
- }
-
- class Program
- {
- static void Main()
- {
-
-
-
- IAccount savingAccount = new SavingAccount();
- Account account = new Account(savingAccount);
- account.PrintAccounts();
-
-
-
-
- IAccount currentAccount = new CurrentAccount();
- account = new Account(currentAccount);
- account.PrintAccounts();
- Console.ReadLine();
- }
- }
Output
Here, I have created a separate "IAccount" interface to make the code loosely coupled. So, we have to use "IAccount" interface to inject SavingAccount & CurrentAccount class objects in Account class constructor. That's why I have Implemented the IAccount interface in SavingAccount and CurrentAccount. If you see the code the "Account" class, there is no class object created. Hence, Account class is not dependent on any other classes and now it is loosely coupled.
I have passed the "IAccount" interface as a parameter to "Account" class constructor to implement constructor DI.
In the main method, If you want to calls the SavingAccount class PrintAccounts() method, just create the object of SavingAccount() and pass as a parameter to Account constructor.
Similarly, In the main method, If you want to call the CurrentAccount class PrintAccounts() method, just create the object of CurrentAccount () and pass as a parameter to Account constructor.
Hence, now there are not classes dependent on each other.
DI using Setter or Property Injection
Setter or property injection is injecting dependent class object through the property. So setter or property injection means, injecting SavingAccount & CurrentAccount class objects in Account class using property. Here the property type will be an interface. Let's see, how we can do this.
-
- public interface IAccount
- {
- void PrintData();
- }
-
-
- public class SavingAccount : IAccount
- {
- public void PrintData()
- {
- Console.WriteLine("Saving account data.");
- }
- }
-
-
- public class CurrentAccount : IAccount
- {
- public void PrintData()
- {
- Console.WriteLine("Current account data.");
- }
- }
-
-
-
- public class Account
- {
-
- public IAccount account { get; set; }
-
- public void PrintAccounts()
- {
- account.PrintData();
- }
- }
-
- class Program
- {
- static void Main()
- {
-
-
-
- Account savingAccount = new Account();
- savingAccount.account = new SavingAccount();
- savingAccount.PrintAccounts();
-
-
-
-
- Account currentAccount = new Account();
- currentAccount.account = new CurrentAccount();
- currentAccount.PrintAccounts();
-
- Console.ReadLine();
- }
- }
Output
DI using Method Injection
Method Injection is injecting dependent class object through a class method. What is mean by this?
In the above example, Account class has a dependency on SavingAccount and CurrentAccount classes. So the method Injection means, injecting SavingAccount & CurrentAccount class objects directly into the Account class method user interface. Let's see how we can do this.
-
- public interface IAccount
- {
- void PrintData();
- }
-
-
- public class SavingAccount : IAccount
- {
- public void PrintData()
- {
- Console.WriteLine("Saving account data.");
- }
- }
-
-
- public class CurrentAccount : IAccount
- {
- public void PrintData()
- {
- Console.WriteLine("Current account data.");
- }
- }
-
-
-
- public class Account
- {
-
- public void PrintAccounts(IAccount account)
- {
- account.PrintData();
- }
- }
-
- class Program
- {
- static void Main()
- {
-
-
-
- Account savingAccount = new Account();
- savingAccount.PrintAccounts(new SavingAccount());
-
-
-
-
- Account currentAccount = new Account();
- currentAccount.PrintAccounts(new CurrentAccount());
-
- Console.ReadLine();
- }
- }
Output
I hope now you are very familiar with DI and types of DI.
Happy coding.......