SOLID Principles in C# - An Overview

SOLID is an acronym and stands for 5 important object oriented principles. The SOLID principles help in making the object oriented application source code robust, scalable, extensible and non-fragile. It is absolutely necessary when you have a layered architecture and they are bound to changes over the period of time. Following are the 5 principles.

1.Single Responsibility Principle

2.Open Closed Principle

3.Liskov Substitution Principle

4.Interface Segregation Principle

5.Dependency Inversion Principle

In this article I will take you through all three all five SOLID principles and also provide sample C# code to demonstrate them.

Single Responsibility Principle (SRP)

SRP states that every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class. There should only be a single reason for making the change to a class.

It means that a class should not be loaded with multiple responsibilities and a single responsibility should not be scattered across multiple classes and mixed with other responsibilities. The reason is that the more changes requested in the future, the more changes the class needs to undergo.

Below is a code violating the SRP. In the sample code, SRP is violated by mixing the OpenGate and CloseGate responsibility with the core vehicle service functionality.

public class ServiceStation
{
    public void OpenGate()
    {
        //Open the gate if the time is later than 9 AM
    }
 
    public void DoService(Vehicle vehicle)
    {
        //Check if service station is opened and then
        //complete the vehicle service
    }
 
    public void CloseGate()
    {
        //Close the gate if the time has crossed 6PM
    }
}

The re-factored code sample is as follows. A new interface is created and the gate related utility methods are moved to a different class called ServiceStationUtility.

public class ServiceStation
{
    IGateUtility _gateUtility;
 
    public ServiceStation(IGateUtility gateUtility)
    {
        this._gateUtility = gateUtility;
    }
    public void OpenForService()
    {
        _gateUtility.OpenGate();
    }
 
    public void DoService()
    {
        //Check if service station is opened and then
        //complete the vehicle service
    }
 
    public void CloseForDay()
    {
        _gateUtility.CloseGate();
    }
}
 
public class ServiceStationUtility : IGateUtility
{
    public void OpenGate()
    {
        //Open the shop if the time is later than 9 AM
    }
 
    public void CloseGate()
    {
        //Close the shop if the time has crossed 6PM
    }
}
 
 
public interface IGateUtility
{
    void OpenGate();
    void CloseGate();
}

Open Closed Principle (OCP)

OCP states that software application source codes should be open for extension but should be closed for modification.

According to the OCP principle the code should be easily extensible but it should not need any changes to be done to the core implementations. Following is a C# source code violating OCP where a new car has to be added then it will require changes in the core function CalculateMileage.

public class MileageCalculator
{
    IEnumerable<Car> _cars;
    public MileageCalculator(IEnumerable<Car> cars) { this._cars = cars; }
 
    public void CalculateMileage()
    {
        foreach (var car in _cars)
        {
            if (car.Name == "Audi")
                Console.WriteLine("Mileage of the car {0} is {1}", car.Name, "10M");
            else if (car.Name == "Mercedes")
                Console.WriteLine("Mileage of the car {0} is {1}", car.Name, "20M");
        }
    }
}

The OCP violation can be fixed as shown below, using an interface and creating classes for each car there, by reducing making the CalculateMileage method more generic and extensible.

public class MileageCalculator
{
    IEnumerable<Car> _cars;
    public MileageCalculator(IEnumerable<Car> cars) { this._cars = cars; }
 
    public void CalculateMileage()
    {
        CarController controller = new CarController();
        foreach (var car in _cars)
        {
                Console.WriteLine("Mileage of the car {0} is {1}", car.Name, controller.GetCarMileage(car.Name));
        }
    }
}
 
public class CarController
{
    List<ICar> cars; 
    public CarController()
    {
        cars = new List<ICar>();
        cars.Add(new Audi());
        cars.Add(new Mercedes());
    }
 
    public string GetCarMileage(string name)
    {
        return cars.First(car => car.Name == name).GetMileage();
    }
}
 
public interface ICar 
{ 
    string Name { get; set; }
    string GetMileage();
}
 
public class Audi : ICar
{
    public string Name { get; set; }
 
    public string GetMileage()
    {
        return "10M";
    }
}
 
public class Mercedes : ICar
{
    public string Name { get; set; }
 
    public string GetMileage()
    {
        return "20M";
    }
}

Liskov Substitution Principle (LSP)

LSP states that the derived classes should be perfectly substitutable for their base classes. If class D is derived from A then D should be substitutable for A.

Look at the following C# code sample where the LSP is broken. Simply, an Orange cannot substitute an Apple, which results in printing the color of apple as Orange.

namespace SolidDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Apple apple = new Orange();
            Console.WriteLine(apple.GetColor());
        }
    }
 
    public class Apple
    {
        public virtual string GetColor()
        {
            return "Red";
        }
    }
 
    public class Orange : Apple
    {
        public override string GetColor()
        {
            return "Orange";
        }
    }
}

Now let us re-factor and make it comply with LSP by having a generic base class for both Apple and Orange.

namespace SolidDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Fruit fruit = new Orange();
            Console.WriteLine(fruit.GetColor());
            fruit = new Apple();
            Console.WriteLine(fruit.GetColor());
        }
    }
 
    public abstract class Fruit
    {
        public abstract string GetColor();
    }
 
    public class Apple : Fruit
    {
        public override string GetColor()
        {
            return "Red";
        }
    }
 
    public class Orange : Apple
    {
        public override string GetColor()
        {
            return "Orange";
        }
    }
}

Interface Segregation Principle (ISP)

ISP states that no clients should be forced to implement methods which it does not use and the contracts should be broken down to thin ones.

Say for example when a thick interface is defined declaring a wide responsibility of members then there will be opportunities where some clients may have to implement members, which they don’t even use. In the below mentioned example ISP is violated where ProcessCreditCard method is not required by InpersonOrder class but is forced to implement.

    public interface IOrder
    {
        void Purchase();
        void ProcessCreditCard();
    }
 
    public class OnlineOrder : IOrder
    {
        public void Purchase()
        {
            //Do purchase
        }
 
        public void ProcessCreditCard()
        {
            //process through credit card
        }
    }
 
    public class InpersionOrder : IOrder
    {
        public void Purchase()
        {
            //Do purchase
        }
 
        public void ProcessCreditCard()
        {
            //Not required for inperson purchase
            throw new NotImplementedException();
        }
    }

Now let us fix the violation by breaking down the IOrder interface.

public interface IOrder
    {
        void Purchase();
    }
 
    public interface IOnlineOrder
    {
        void ProcessCreditCard();
    }
 
    public class OnlineOrder : IOrder, IOnlineOrder
    {
        public void Purchase()
        {
            //Do purchase
        }
 
        public void ProcessCreditCard()
        {
            //process through credit card
        }
    }
 
    public class InpersionOrder : IOrder
    {
        public void Purchase()
        {
            //Do purchase
        }
    }

Dependency Inversion Principle (DIP)

DIP states that the higher level modules should be coupled with the lower level modules with complete abstraction.

You can read more about DIP and IoC in my earlier article where I have covered it in-depth. Please check here.

I hope this article took you through SOLID principles with appropriate C# code samples. Happy reading!



Related Articles

Comments

  • Implementing proper work have good

    Posted by bfyolsWP on 07/09/2013 09:01pm

    http://fuciki.asia/cheapghds/ ghd straightners

    Reply
  • to the moon breathtaking cup 2014 brazil soccer jerseys aborigine realty wishes coming this biggest soccer party.

    Posted by Merejensejage on 06/25/2013 05:28pm

    Burnley winger Fernando [url=http://www.worldcupsoccerfacts.info/]2014 world cup soccer jerseys[/url] Guerrero has severed his ties with the club [url=http://www.worldcupsoccerfacts.info/]wholesale soccer [url=http://www.worldcupsoccerfacts.info/]wholesale soccer jerseys[/url] jerseys[/url] after cutting short a season-long loan deal.The Ecuadorian joined on a temporary basis from Independiente del Valle last summer with a view to securing a permanent transfer.However, after just seven Premier League substitute appearances - the last on 12 December - the 20-year-old has had his loan terminated.

    Reply
  • yxUVMN ic Dr uQT iBkK Uv

    Posted by hbKSTVNziD on 06/24/2013 10:48pm

    site oficial generic viagra gold - buy-genericviagra

    Reply
  • wheloltabotly PumeSonee Phobereurce 671533

    Posted by TizefaTaNaday on 05/16/2013 06:46am

    Speerstep PiontavotsSot LONOGYMOURN

    Reply
  • wheloltabotly PumeSonee Phobereurce 4217301

    Posted by TizefaTaNaday on 05/16/2013 01:35am

    Tubimpuby http://www.lexoutdoorpower.com/images/index.php?celine-blogg-are-so-fashion-and-graceful-that-attract-much-attention-and-become-the-best-sellers-recently.html Seveviage http://www.jschnabeldesigns.com/images/index.php?lv-speedy-30-azurlouis-vuittonsale-online.html thicyAdmicy

    Reply
  • wheloltabotly PumeSonee Phobereurce 5345263

    Posted by TizefaTaNaday on 05/13/2013 03:57am

    suildflieme http://www.stoneadvisory.com/W3SVC32/index.php?2010-prada-menswear-prada-shop-online.html alabyDaycle http://www.cssiky.com/Brester/index.asp?fendi-prada-bagspradacoupon-online.html TewcrocaOceal

    Reply
  • Mr.

    Posted by bustiuci on 05/07/2013 11:35am

    Nice article ... congrats.

    Reply
  • Architect Microsoft technologies

    Posted by Venkatesh on 05/06/2013 06:25pm

    In OCP, I think instead of having a separate classes for the cars, it would be good if you had stated that the usage of Configuration file. I feel taking the config file route of extensibility is more appropriate for these kinds of requirement rather than having classes

    Reply
  • OCP

    Posted by Salam on 05/06/2013 12:40pm

    Hi, interesting thread. can you please share how can we call the code for the 2nd item OCP, I am a little bit confused as in some places like in class MileageCalculator you use , a constructor which requires an argument of type "IEnumerable cars", the initiate the controller but never used and then you loop into "cars" which is empty Thanks in advance

    Reply
  • Senior Swiss knife

    Posted by Emmanuel Deloget on 05/06/2013 06:51am

    No offense intended, but your orange is still an apple :) (I guess you wanted it to inherit Fruit)

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • With JRebel, developers get to see their code changes immediately, fine-tune their code with incremental changes, debug, explore and deploy their code with ease (both locally and remotely), and ultimately spend more time coding instead of waiting for the dreaded application redeploy to finish. Every time a developer tests a code change it takes minutes to build and deploy the application. JRebel keeps the app server running at all times, so testing is instantaneous and interactive.

  • As businesses have grown in size and global reach, emerging technologies such as cloud computing and virtualization have appeared to help companies effectively connect and grow. However, the networking strategies and infrastructures that keep organizations connected have often remained in the past. Now, new strategies that leverage global connectivity and locations exist to provide a more flexible and cost-effective alternative to traditional networking systems. This Aberdeen report analyzes how top performing …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds