Menu

C# – Solid principles with C# examples

Solid principles are a set of design principles that help developers create maintainable, scalable, and flexible software. Regardless of the programming language you use, SOLID will help you write more liner, maintainable, extendable code.

The SOLID acronym stands for:

S – Single Responsibility Principle
O – Open/Closed Principle
L – Liskov Substitution Principle
I – Interface Segregation Principle
D – Dependency Inversion Principle

Let’s see them in more detail

Single Responsibility Principle
A class should have only one reason to change.

// Without Single Responsibility Principle 
public class Report 
{ 
  public void GenerateReport() 
  { 
   // Generate report logic 
  } 

  public void SaveReportToFile() 
  { 
   // Save report to file logic 
  } 
} 


// With Single Responsibility Principle 
public class Report 
{ 
  public void GenerateReport() 
  { 
    // Generate report logic 
  } 
}

public class ReportSaver 
{ 
  public void SaveReportToFile(Report report) 
  { 
     // Save report to file logic 
  }
}

 

Open/Closed Principle
Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.

// Without Open/Closed Principle
public class Rectangle 
{
 public double Width { get; set; }
 public double Height { get; set; }
}

public class AreaCalculator 
{
  public double CalculateArea(Rectangle rectangle) 
  {
    return rectangle.Width * rectangle.Height;
  }
}

// Adding a new shape requires modifying existing code
public class Circle 
{
  public double Radius { get; set; }
}


// With Open/Closed Principle
public abstract class Shape 
{
  public abstract double CalculateArea();
}

public class Rectangle : Shape 
{
  public double Width { get; set; }
  public double Height { get; set; }

  public override double CalculateArea()
  {
    return Width * Height;
  }
}

public class Circle : Shape 
{
  public double Radius { get; set; }

  public override double CalculateArea() 
  {
    return Math.PI * Radius * Radius;
  }
}

 

Liskov Substitution Principle
Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program.

// Without Liskov Substitution Principle
public class Bird 
{
  public virtual void Fly() 
  {
    Console.WriteLine("Bird is flying");
  }
}

public class Ostrich : Bird 
{
  public override void Fly() 
  {
    // Ostrich can't fly, violates LSP
    Console.WriteLine("Ostrich can't fly");
  }
}


// With Liskov Substitution Principle
public interface IFlyable 
{
  void Fly();
}

public class Bird : IFlyable 
{
  public void Fly() 
  {
    Console.WriteLine("Bird is flying");
  }
}

public class Ostrich : IFlyable 
{
  public void Fly() 
  {
    // Ostrich can't fly, conforms to LSP
    Console.WriteLine("Ostrich can't fly");
  }
}

 

Interface Segregation Principle
A client should not be forced to implement interfaces it does not use.

// Without Interface Segregation Principle
public interface IWorker 
{
  void Work();
  void Eat();
}

public class Worker : IWorker 
{
  public void Work() 
  {
    // Work logic
  }
  
  public void Eat() 
  {
     // Eat logic
  }
}

// With Interface Segregation Principle
public interface IWorkable 
{
  void Work();
}

public interface IEatable 
{
  void Eat();
}

public class Worker : IWorkable, IEatable 
{
  public void Work() 
  {
    // Work logic
  }

  public void Eat() 
  {
  // Eat logic
  }
}

 

Dependency Inversion Principle
High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details; details should depend on abstractions.

// Without Dependency Inversion Principle
public class LightBulb 
{
  public void TurnOn() 
  {
    // Turn on logic
  }
}

public class Switch 
{
  private LightBulb bulb;public Switch() 
  {
    bulb = new LightBulb();
  }

  public void Toggle()
  {
    // Toggle logic
    bulb.TurnOn();
  }
}

// With Dependency Inversion Principle
public interface ISwitchable 
{
  void TurnOn();
}

public class LightBulb : ISwitchable 
{
  public void TurnOn() 
  {
    // Turn on logic
  }
}

public class Switch 
{
  private ISwitchable device;

  public Switch(ISwitchable device) 
  {
    this.device = device;
  }

  public void Toggle() 
  {
    // Toggle logic
    device.TurnOn();
  }
}

These simple examples will help us remember

Leave a comment