C# Single Responsibility Principle

Summary: in this tutorial, you’ll learn how to use the C# Single Responsibility Principle to develop software applications that are more maintainable and scalable.

Introduction to the C# single responsibility principle

The Single Responsibility Principle (SRP) is the first principle in the five SOLID principles:

The Single Responsibility Principle states that a software module should have a single responsibility, i.e., it should have one and only one reason to change.

In C#, a software module can be a class or a method of a class. The responsibility refers to the purpose or concern that a class has in an application.

By having a single responsibility, a class becomes more cohesive and easier to maintain. It also makes the application more flexible, as changes to one responsibility do not impact other responsibilities.

For example, a class responsible for representing data should only have the responsibility of holding the data. It should not be responsible for saving the data to a database or performing any other unrelated tasks.

By separating these responsibilities into separate classes, the application becomes more maintainable and easier to extend.

C# Single Responsibility Principle example

Suppose you need to create a program to manage invoices:

public class Invoice
{
    public int InvoiceNo {  get; set; }
    public DateOnly IssuedDate { get; set; }
    public string? Customer { get; set; }
    public decimal Amount { get; set; }
    public string? Description { get; set;}

    public void Save()
    {
        Console.WriteLine($"Saved the invoice #{InvoiceNo}");
    }

}

class Program
{
    public static void Main(string[] args)
    {
        // create a new invoice
        var invoice = new Invoice
        {
            InvoiceNo = 1,
            Customer = "John Doe",
            IssuedDate = new DateOnly(2023, 4, 1),
            Description = "Website Design",
            Amount = 1000
        };

        invoice.Save();

    }
}Code language: C# (cs)

How it works.

First, define an Invoice class that has properties InvoiceNo, Customer, IssuedDate, Description, and Amount. The Invoice class also has the Save() method that saves an invoice into a database:

public class Invoice
{
    public int InvoiceNo {  get; set; }
    public DateOnly IssuedDate { get; set; }
    public string? Customer { get; set; }
    public decimal Amount { get; set; }
    public string? Description { get; set;}

    public void Save()
    {
        Console.WriteLine($"Saved the invoice #{InvoiceNo}");
    }

}Code language: C# (cs)

For demonstration purposes, the Save() method displays a message in the console instead of saving an invoice to a real database.

Second, create an invoice in the Main() method of the Program class and call the Save() method to save the invoice:

class Program
{
    public static void Main(string[] args)
    {
        // create a new invoice
        var invoice = new Invoice
        {
            InvoiceNo = 1,
            Customer = "John Doe",
            IssuedDate = new DateOnly(2023, 4, 1),
            Description = "Website Design",
            Amount = 1000
        };

        invoice.Save();

    }
}Code language: C# (cs)

Initially, the Invoice class looks fine. But when the program is getting bigger, you’ll realize that the Invoice class has multiple responsibilities.

The Invoice class not only represents the invoice data but also is responsible for saving the invoice into storage. This violates the single responsibility principle as the Invoice class should have a single responsibility.

Let’s refactor the Invoice class to follow the single responsibility principle.

Refactoring the Invoice class to follow the single responsibility principle

First, create a separate class called InvoiceRepository for saving an invoice and moving the Save() method from the Invoice class to the InvoiceRepository class:

class InvoiceRepository
{
    public void Save(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo}");
    }
}Code language: C# (cs)

Now, the Invoice class has a single responsibility that represents invoice data only. Also, the InvoiceRepository is solely responsible for saving the invoice.

public class Invoice
{
    public int InvoiceNo { get;set; }
    public DateOnly IssuedDate { get; set; }
    public string? Customer { get; set;}
    public decimal Amount { get; set; }
    public string? Description { get; set;}
}Code language: C# (cs)

Second, create an invoice and save it to a database by calling the Save() of the InvoiceRepository class:

class Program
{
    public static void Main(string[] args)
    {
        // create a new invoice
        var invoice = new Invoice
        {
            InvoiceNo = 1,
            Customer = "John Doe",
            IssuedDate = new DateOnly(2023, 4, 1),
            Description = "Website Design",
            Amount = 1000
        };

        // save the invoice to a storage
        var invoiceRepository = new InvoiceRepository();
        invoiceRepository.Save(invoice);
    }
}Code language: C# (cs)

Put it all together.

public class Invoice
{
    public int InvoiceNo { get;set; }
    public DateOnly IssuedDate { get; set; }
    public string? Customer { get; set;}
    public decimal Amount { get; set; }
    public string? Description { get; set;}
}

class InvoiceRepository
{
    public void Save(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo}");
    }
}

class Program
{
    public static void Main(string[] args)
    {
        // create a new invoice
        var invoice = new Invoice
        {
            InvoiceNo = 1,
            Customer = "John Doe",
            IssuedDate = new DateOnly(2023, 4, 1),
            Description = "Website Design",
            Amount = 1000
        };

        // save the invoice to a storage
        var invoiceRepository = new InvoiceRepository();
        invoiceRepository.Save(invoice);
    }
}Code language: C# (cs)

Summary

  • The Single Responsibility Principle states that a module should have only one reason to change.
Was this tutorial helpful ?