Dependency Injection is decoupling the usage of an object from it’s creation. An abstraction is created between a higher level class and it’s dependencies.
In the below example, the Notification service (lower level module) is abstracted from the higher level class User.
Create Interface as below:
public interface INotification
{
void SendNotification(User user);
}
Create a class that implements the above interface:
public class ConsoleNotification: INotification
{
public void SendNotification(User user)
{
Console.WriteLine($"Changed name to: {user.username}");
}
}
There can be other classes like EmailNotification that implements this interface.
Now, create a class called User that would require to send notification to a user:
public class User
{
public string username { get; private set; }
INotification _notify;
public User(string name, INotification notify)
{
username = name;
_notify = notify;
}
public void changeName(string name)
{
username = name;
_notify.SendNotification(this);
}
}
In the above code, if the User class was itself creating the ConsoleNotification object, that would have been tight coupling between the 2 classes. So, if we wanted to change the Notification service to EmailNotification, we would have to change the User class directly.
The client which in our case is the Program.cs code, will pass the ConsoleNotification object to the user object in the Constructor which is called Constructor injection.
class Program
{
static void Main(string[] args)
{
var notify = new ConsoleNotification();
//Passing ConsoleNotification type, could be any other type implementing INotification..
var user1 = new User("Tim", notify);
Console.WriteLine($"User Name: {user1.username}");
user1.changeName("Jim");
Console.ReadKey();
}
}
Output:
User Name: Tim
Changed name to: Jim
So, the User class is not directly creating a dependency on a particular type of notification Service. Rather the client is telling at run-time what instance of notification service the User class should use which is also called inversion of control (IoC). We’re creating the object of the dependency first and then injecting it into the higher level object.