Dependency Inversion Principle (DIP)


In this article we are going to discuss Dependency Inversion Principle (DIP) in C#. There are many blogs, articles are available on the internet regarding Dependency Inversion Principle (DIP) but in this particular article I will try to explain to you with as much as simple.

Dependency Inversion Principle (DIP)

The Dependency Inversion Principle (DIP) is the last of the SOLID principles. It states that high-level modules should not depend on low-level modules. Both should depend on abstractions. Additionally, abstractions should not depend on details. Details should depend on abstractions.

Violating the Dependency Inversion Principle

Here’s an example where the DIP is violated. we can create an example where high-level modules depend directly on low-level modules, without abstraction, which violates the principle.

Example

// Low-level module
public class EmailSender
{
    public void SendEmail(string message)
    {
        Console.WriteLine($"Email sent: {message}");
    }
}

// High-level module directly depends on the low-level module
public class NotificationService
{
    private readonly EmailSender _emailSender;

    public NotificationService()
    {
        _emailSender = new EmailSender(); // Direct dependency on concrete class
    }

    public void Notify(string message)
    {
        _emailSender.SendEmail(message);
    }
}

class Program
{
    static void Main(string[] args)
    {
        NotificationService notificationService = new NotificationService();
        notificationService.Notify("Hello, DIP violation!");
    }
}

The high-level module (NotificationService) is tightly coupled to the low-level module (EmailSender). Any changes in EmailSender may require changes in NotificationService, violating the Open-Closed Principle (OCP).

With Dependency Inversion Principle

To adhere to the DIP, you should introduce an abstraction (interface or abstract class) between NotificationService and EmailSender.

Example

public interface IMessageSender
{
    void SendMessage(string message);
}
public class EmailSender : IMessageSender
{
    public void SendMessage(string message)
    {
        Console.WriteLine($"Email sent: {message}");
    }
}

public class SmsSender : IMessageSender
{
    public void SendMessage(string message)
    {
        Console.WriteLine($"SMS sent: {message}");
    }
}
public class NotificationService
{
    private readonly IMessageSender _messageSender;

    public NotificationService(IMessageSender messageSender)
    {
        _messageSender = messageSender;
    }

    public void Notify(string message)
    {
        _messageSender.SendMessage(message);
    }
}

class Program
{
    static void Main(string[] args)
    {
        IMessageSender emailSender = new EmailSender();
        NotificationService notificationService = new NotificationService(emailSender);

        notificationService.Notify("Hello via Email!");

        IMessageSender smsSender = new SmsSender();
        notificationService = new NotificationService(smsSender);

        notificationService.Notify("Hello via SMS!");
    }
}

Output

Dependency Inversion Principal in C#
Prev Next