SOLID Principles

Implementing DIP in C#

To adhere to the Dependency Inversion Principle in C#, you can use interfaces or abstract classes to create abstractions that high-level and low-level modules depend on.

Example: Notification System

Consider an example where a user registration system sends a notification to the user upon registration.

Violating DIP

In this example, the UserService directly depends on the EmailService class.


public class EmailService
{
    public void SendEmail(string to, string subject, string body)
    {
        // Code to send email
    }
}

public class UserService
{
    private EmailService _emailService;

    public UserService()
    {
        _emailService = new EmailService();
    }

    public void RegisterUser(string email, string password)
    {
        // Code to register user

        // Send notification
        _emailService.SendEmail(email, "Welcome!", "Thank you for registering.");
    }
}

In this design, if you need to switch to a different notification mechanism (e.g., SMS), you would have to modify the UserService class, which violates DIP.

Adhering to DIP

To adhere to DIP, introduce an abstraction (interface) for the notification service.


public interface INotificationService
{
    void Notify(string to, string message);
}

public class EmailService : INotificationService
{
    public void Notify(string to, string message)
    {
        // Code to send email
    }
}

public class SmsService : INotificationService
{
    public void Notify(string to, string message)
    {
        // Code to send SMS
    }
}

public class UserService
{
    private readonly INotificationService _notificationService;

    public UserService(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }

    public void RegisterUser(string email, string password)
    {
        // Code to register user

        // Send notification
        _notificationService.Notify(email, "Thank you for registering.");
    }
}

In this design, the UserService class depends on the INotificationService interface, an abstraction, rather than a concrete class. This allows you to easily switch to a different notification service without modifying the UserService class.