SOLID principles in C#
SOLID design principles in C# are basic design principles. SOLID stands for Single Responsibility Principle (SRP), Open closed Principle (OSP), Liskov substitution Principle (LSP), Interface Segregation Principle (ISP), and Dependency Inversion Principle (DIP).
Basics of SOLID design principles using C# and . NET.
- The reasons behind most unsuccessful applications
- Solutions
- Intro to SOLID principles
- SRP
- OCP
- LSP
- ISP
- DIP

The reason behind most unsuccessful applications
Developers build applications with good and tidy designs using their knowledge and experience. But over time, applications might develop bugs. The application design must be altered for every change request or new feature request. After some time, we might need to put in a lot of effort, even for simple tasks, and it might require a full working knowledge of the entire system. But we can't blame change or new feature requests. They are part of software development. We can't stop them or refuse them either. So who is the culprit here? It is the design of the application.
The following are the design flaws that cause damage to software, mostly.
- Putting more stress on classes by assigning more responsibilities to them. (A lot of functionality not related to a class.)
- Forcing the classes to depend on each other. If classes depend on each other (in other words, tightly coupled), then a change in one will affect the other.
- Spreading duplicate code in the system/application.
Solution
- Choosing the correct architecture (MVC, 3-tier, Layered, MVP, MVVP, and so on).
- Following Design Principles.
- Choosing the correct Design Patterns to build the software based on its specifications. We go through the Design Principles first and will cover the rest soon.
Introduction to SOLID principles
SOLID principles are the design principles that enable us to manage several software design problems. Robert C. Martin compiled these principles in the 1990s. These principles provide us with ways to move from tightly coupled code and little encapsulation to the desired results of loosely coupled and encapsulated real business needs properly. SOLID is an acronym for the following.
- S: Single Responsibility Principle (SRP)
- O: Open-closed Principle (OCP)
- L: Liskov substitution Principle (LSP)
- I: Interface Segregation Principle (ISP)
- D: Dependency Inversion Principle (DIP)
S: Single Responsibility Principle (SRP)
SRP says, "Every software module should have only one reason to change.".

This means that every class or similar structure in your code should have only one job. Everything in that class should be related to a single purpose. Our class should not be like a Swiss knife wherein if one of them needs to be changed, the entire tool needs to be altered. It does not mean that your classes should only contain one method or property. There may be many members as long as they relate to a single responsibility.
The Single Responsibility Principle gives us a good way of identifying classes at the design phase of an application, and it makes you think of all the ways a class can change. However, a good separation of responsibilities is done only when we have the full picture of how the application should work. Let us check this with an example.
public class UserService
{
public void Register(string email, string password)
{
if (!ValidateEmail(email))
throw new ValidationException("Email is not an email");
var user = new User(email, password);
SendEmail(new MailMessage("[email protected]", email) { Subject="HEllo foo" });
}
public virtual bool ValidateEmail(string email)
{
return email.Contains("@");
}
public bool SendEmail(MailMessage message)
{
_smtpClient.Send(message);
}
}
It looks fine, but it is not following SRP. The SendEmail and ValidateEmail methods have nothing to do with the UserService class. Let's refract it.
public class UserService
{
EmailService _emailService;
DbContext _dbContext;
public UserService(EmailService aEmailService, DbContext aDbContext)
{
_emailService = aEmailService;
_dbContext = aDbContext;
}
public void Register(string email, string password)
{
if (!_emailService.ValidateEmail(email))
throw new ValidationException("Email is not an email");
var user = new User(email, password);
_dbContext.Save(user);
emailService.SendEmail(new MailMessage("[email protected]", email) {Subject="Hi. How are you!"});
}
}
public class EmailService
{
SmtpClient _smtpClient;
public EmailService(SmtpClient aSmtpClient)
{
_smtpClient = aSmtpClient;
}
public bool virtual ValidateEmail(string email)
{
return email.Contains("@");
}
public bool SendEmail(MailMessage message)
{
_smtpClient.Send(message);
}
}
O: Open/Closed Principle
The Open/closed Principle says, "A software module/class is open for extension and closed for modification."

Here "Open for extension" means we must design our module/class so that the new functionality can be added only when new requirements are generated. "Closed for modification" means we have already developed a class, and it has gone through unit testing. We should then not alter it until we find bugs. As it says, a class should be open for extensions; we can use inheritance. OK, let's dive into an example.
Suppose we have a Rectangle class with the properties Height and Width.
public class Rectangle{
public double Height {get;set;}
public double Wight {get;set; }
}
Our app needs to calculate the total area of a collection of Rectangles. Since we already learned the Single Responsibility Principle (SRP), we don't need to put the total area calculation code inside the rectangle. So here, I created another class for area calculation.
public class AreaCalculator {
public double TotalArea(Rectangle[] arrRectangles)
{
double area;
foreach(var objRectangle in arrRectangles)
{
area += objRectangle.Height * objRectangle.Width;
}
return area;
}
}
Hey, we did it. We made our app without violating SRP. No issues for now. But can we extend our app so that it can calculate the area of not only Rectangles but also the area of Circles? Now we have an issue with the area calculation issue because the way to calculate the circle area is different. Hmm. Not a big deal. We can change the TotalArea method to accept an array of objects as an argument. We check the object type in the loop and do area calculations based on the object type.
public class Rectangle{
public double Height {get;set;}
public double Wight {get;set; }
}
public class Circle{
public double Radius {get;set;}
}
public class AreaCalculator
{
public double TotalArea(object[] arrObjects)
{
double area = 0;
Rectangle objRectangle;
Circle objCircle;
foreach(var obj in arrObjects)
{
if(obj is Rectangle)
{
area += obj.Height * obj.Width;
}
else
{
objCircle = (Circle)obj;
area += objCircle.Radius * objCircle.Radius * Math.PI;
}
}
return area;
}
}
Wow. We are done with the change. Here we successfully introduced Circle into our app. We can add a Triangle and calculate its area by adding one more "if" block in the TotalArea method of AreaCalculator. But every time we introduce a new shape, we must alter the TotalArea method. So the AreaCalculator class is not closed for modification. How can we make our design to avoid this situation? Generally, we can do this by referring to abstractions for dependencies, such as interfaces or abstract classes, rather than using concrete classes. Such interfaces can be fixed once developed so the classes that depend upon them can rely upon unchanging abstractions. Functionality can be added by creating new classes that implement the interfaces. So let's refract our code using an interface.
public abstract class Shape
{
public abstract double Area();
}
Inheriting from Shape, the Rectangle and Circle classes now look like this:
public class Rectangle: Shape
{
public double Height {get;set;}
public double Width {get;set;}
public override double Area()
{
return Height * Width;
}
}
public class Circle: Shape
{
public double Radius {get;set;}
public override double Area()
{
return Radius * Radus * Math.PI;
}
}
Every shape contains its area with its way of calculation functionality, and our AreaCalculator class will become simpler than before.
public class AreaCalculator
{
public double TotalArea(Shape[] arrShapes)
{
double area=0;
foreach(var objShape in arrShapes)
{
area += objShape.Area();
}
return area;
}
}
Now our code is following SRP and OCP both. Whenever you introduce a new shape by deriving from the "Shape" abstract class, you need not change the "AreaCalculator" class. Awesome. Isn't it?
L: Liskov Substitution Principle

The Liskov Substitution Principle (LSP) states, "you should be able to use any derived class instead of a parent class and have it behave in the same manner without modification.". It ensures that a derived class does not affect the behavior of the parent class; in other words, a derived class must be substitutable for its base class.
This principle is just an extension of the Open Closed Principle, and we must ensure that newly derived classes extend the base classes without changing their behavior. I will explain this with a real-world example that violates LSP.
A father is a doctor, whereas his son wants to become a cricketer. So here, the son can't replace his father even though they belong to the same family hierarchy.
Now jump into an example to learn how a design can violate LSP. Suppose we need to build an app to manage data using a group of SQL files text. Here we need to write functionality to load and save the text of a group of SQL files in the application directory. So we need a class that manages the load and keeps the text of a group of SQL files along with the SqlFile Class.
public class SqlFile
{
public string FilePath {get;set;}
public string FileText {get;set;}
public string LoadText()
{
/* Code to read text from sql file */
}
public string SaveText()
{
/* Code to save text into sql file */
}
}
public class SqlFileManager
{
public List<SqlFile> lstSqlFiles {get;set}
public string GetTextFromFiles()
{
StringBuilder objStrBuilder = new StringBuilder();
foreach(var objFile in lstSqlFiles)
{
objStrBuilder.Append(objFile.LoadText());
}
return objStrBuilder.ToString();
}
public void SaveTextIntoFiles()
{
foreach(var objFile in lstSqlFiles)
{
objFile.SaveText();
}
}
}
OK. We are done with our part. The functionality looks good for now. However, after some time, our leaders might tell us that we may have a few read-only files in the application folder, so we must restrict the flow whenever it tries to save them.
OK. We need to modify "SqlFileManager" by adding one condition to the loop to avoid an exception. We can do that by creating a "ReadOnlySqlFile" class that inherits the "SqlFile" class, and we need to alter the SaveTextIntoFiles() method by introducing a condition to prevent calling the SaveText() method on ReadOnlySqlFile instances.
public class SqlFileManager
{
public List<SqlFile? lstSqlFiles {get;set}
public string GetTextFromFiles()
{
StringBuilder objStrBuilder = new StringBuilder();
foreach(var objFile in lstSqlFiles)
{
objStrBuilder.Append(objFile.LoadText());
}
return objStrBuilder.ToString();
}
public void SaveTextIntoFiles()
{
foreach(var objFile in lstSqlFiles)
{
//Check whether the current file object is read-only or not.If yes, skip calling it's
// SaveText() method to skip the exception.
if(! objFile is ReadOnlySqlFile)
objFile.SaveText();
}
}
}
Here we altered the SaveTextIntoFiles() method in the SqlFileManager class to determine whether or not the instance is of ReadOnlySqlFile to avoid the exception. We can't use this ReadOnlySqlFile class as a substitute for its parent without altering the SqlFileManager code. So we can say that this design is not following LSP. Let's make this design follow the LSP. Here we will introduce interfaces to make the SqlFileManager class independent from the rest of the blocks.
public interface IReadableSqlFile
{
string LoadText();
}
public interface IWritableSqlFile
{
void SaveText();
}
Now we implement IReadableSqlFile through the ReadOnlySqlFile class that reads only the text from read-only files. We implement both IWritableSqlFile and IReadableSqlFile in a SqlFile class by which we can read and write files.
public class SqlFile: IWritableSqlFile,IReadableSqlFile
{
public string FilePath {get;set;}
public string FileText {get;set;}
public string LoadText()
{
/* Code to read text from sql file */
}
public void SaveText()
{
/* Code to save text into sql file */
}
}
Now the design of the SqlFileManager class becomes like this.
public class SqlFileManager
{
public string GetTextFromFiles(List<IReadableSqlFile> aLstReadableFiles)
{
StringBuilder objStrBuilder = new StringBuilder();
foreach(var objFile in aLstReadableFiles)
{
objStrBuilder.Append(objFile.LoadText());
}
return objStrBuilder.ToString();
}
public void SaveTextIntoFiles(List<IWritableSqlFile> aLstWritableFiles)
{
foreach(var objFile in aLstWritableFiles)
{
objFile.SaveText();
}
}
}
Here the GetTextFromFiles() method gets only the list of instances of classes that implement the IReadOnlySqlFile interface. That means the SqlFile and ReadOnlySqlFile class instances. And the SaveTextIntoFiles() method gets only the list instances of the class that implements the IWritableSqlFiles interface, in this case, SqlFile instances. So now we can say our design is following the LSP. And we fixed the problem using the Interface segregation principle (ISP), identifying the abstraction and the responsibility separation method.
I: Interface Segregation Principle (ISP)
The Interface Segregation Principle states "that clients should not be forced to implement interfaces they don't use. Instead of one fat interface, many small interfaces are preferred based on groups of methods, each serving one submodule.".

We can define it in another way. An interface should be more closely related to the code that uses it than the code that implements it. So the methods on the interface are defined by which methods the client code needs rather than which methods the class implements. So clients should not be forced to depend upon interfaces they don't use.
Like classes, each interface should have a specific purpose/responsibility (refer to SRP). You shouldn't be forced to implement an interface when your object doesn't share that purpose. The larger the interface, the more likely it includes methods not all implementers can use. That's the essence of the Interface Segregation Principle. Let's start with an example that breaks the ISP. Suppose we need to build a system for an IT firm that contains roles like TeamLead and Programmer where TeamLead divides a huge task into smaller tasks and assigns them to his/her programmers or can directly work on them.
Based on specifications, we need to create an interface and a TeamLead class to implement it.
public Interface ILead
{
void CreateSubTask();
void AssginTask();
void WorkOnTask();
}
public class TeamLead : ILead
{
public void AssignTask()
{
//Code to assign a task.
}
public void CreateSubTask()
{
//Code to create a sub task
}
public void WorkOnTask()
{
//Code to implement perform assigned task.
}
}
OK. The design looks fine for now. However, later another role, like Manager, who assigns tasks to TeamLead and will not work on the tasks, is introduced into the system. Can we directly implement an ILead interface in the Manager class, like the following?
public class Manager: ILead
{
public void AssignTask()
{
//Code to assign a task.
}
public void CreateSubTask()
{
//Code to create a sub task.
}
public void WorkOnTask()
{
throw new Exception("Manager can't work on Task");
}
}
Since the Manager can't work on a task and, at the same time, no one can assign tasks to the Manager, this WorkOnTask() should not be in the Manager class. But we are implementing this class from the ILead interface; we must provide a concrete Method. Here we are forcing the Manager class to implement a WorkOnTask() method without a purpose. This is wrong. The design violates ISP. Let's correct the design.
Since we have three roles, 1, managers can only divide and assign tasks, 2. TeamLead can divide and assign the jobs and work on them, 3. We need to divide the responsibilities by segregating the ILead interface for the programmer that can only work on tasks—an interface that provides a contract for WorkOnTask().
public interface IProgrammer
{
void WorkOnTask();
}
An interface that provides contracts to manage the tasks:
public interface ILead
{
void AssignTask();
void CreateSubTask();
}
Then the implementation becomes.
public class Programmer: IProgrammer
{
public void WorkOnTask()
{
//code to implement to work on the Task.
}
}
public class Manager: ILead
{
public void AssignTask()
{
//Code to assign a Task
}
public void CreateSubTask()
{
//Code to create a sub taks from a task.
}
}
TeamLead can manage tasks and can work on them if needed. Then the TeamLead class should implement both the IProgrammer and ILead interfaces.
public class TeamLead: IProgrammer, ILead
{
public void AssignTask()
{
//Code to assign a Task
}
public void CreateSubTask()
{
//Code to create a sub task from a task.
}
public void WorkOnTask()
{
//code to implement to work on the Task.
}
}
Wow. Here we separated responsibilities/purposes, distributed them on multiple interfaces, and provided good abstraction.
D: Dependency Inversion Principle
The Dependency Inversion Principle (DIP) states that high-level modules/classes should not depend on low-level modules/classes. First, both should depend upon abstractions. Secondly, abstractions should not rely upon details. Finally, details should depend upon abstractions.

High-level modules/classes implement business rules or logic in a system (application). Low-level modules/classes deal with more detailed operations; in other words, they may write information to databases or pass messages to the operating system or services.
A high-level module/class that depends on low-level modules/classes or some other class and knows a lot about the other classes it interacts with is said to be tightly coupled. When a class knows explicitly about the design and implementation of another class, it raises the risk that changes to one class will break the other. So we must keep these high-level and low-level modules/classes loosely coupled as much as possible. To do that, we need to make both of them dependent on abstractions instead of knowing each other. Let's start with an example.
Suppose we need to work on an error-logging module that logs exception stack traces into a file. Simple, isn't it? The following classes provide the functionality to log a stack trace into a file.
public class FileLogger
{
public void LogMessage(string aStackTrace)
{
//code to log stack trace into a file.
}
}
public class ExceptionLogger
{
public void LogIntoFile(Exception aException)
{
FileLogger objFileLogger = new FileLogger();
objFileLogger.LogMessage(GetUserReadableMessage(aException));
}
private GetUserReadableMessage(Exception ex)
{
string strMessage = string. Empty;
//code to convert Exception's stack trace and message to user readable format.
....
....
return strMessage;
}
}
A client class exports data from many files to a database.
public class DataExporter
{
public void ExportDataFromFile()
{
try {
//code to export data from files to the database.
}
catch(Exception ex)
{
new ExceptionLogger().LogIntoFile(ex);
}
}
}
Looks good. We sent our application to the client. But our client wants to store this stack trace in a database if an IO exception occurs. Hmm... OK, no problem. We can implement that too. Here we need to add one more class that provides the functionality to log the stack trace into the database and an extra method in ExceptionLogger to interact with our new class to log the stack trace.
public class DbLogger
{
public void LogMessage(string aMessage)
{
//Code to write message in the database.
}
}
public class FileLogger
{
public void LogMessage(string aStackTrace)
{
//code to log stack trace into a file.
}
}
public class ExceptionLogger
{
public void LogIntoFile(Exception aException)
{
FileLogger objFileLogger = new FileLogger();
objFileLogger.LogMessage(GetUserReadableMessage(aException));
}
public void LogIntoDataBase(Exception aException)
{
DbLogger objDbLogger = new DbLogger();
objDbLogger.LogMessage(GetUserReadableMessage(aException));
}
private string GetUserReadableMessage(Exception ex)
{
string strMessage = string.Empty;
//code to convert Exception's stack trace and message to user readable format.
....
....
return strMessage;
}
}
public class DataExporter
{
public void ExportDataFromFile()
{
try {
//code to export data from files to database.
}
catch(IOException ex)
{
new ExceptionLogger().LogIntoDataBase(ex);
}
catch(Exception ex)
{
new ExceptionLogger().LogIntoFile(ex);
}
}
}
Looks fine for now. But whenever the client wants to introduce a new logger, we must alter ExceptionLogger by adding a new method. Suppose we continue doing this after some time. In that case, we will see a fat ExceptionLogger class with a large set of practices that provide the functionality to log a message into various targets. Why does this issue occur? Because ExceptionLogger directly contacts the low-level classes FileLogger and DbLogger to log the exception. We need to alter the design so that this ExceptionLogger class can be loosely coupled with those classes. To do that, we need to introduce an abstraction between them so that ExcetpionLogger can contact the abstraction to log the exception instead of directly depending on the low-level classes.
public interface ILogger
{
void LogMessage(string aString);
}
Now our low-level classes need to implement this interface.
public class DbLogger: ILogger
{
public void LogMessage(string aMessage)
{
//Code to write message in database.
}
}
public class FileLogger: ILogger
{
public void LogMessage(string aStackTrace)
{
//code to log stack trace into a file.
}
}
Now, we move to the low-level class's initiation from the ExcetpionLogger class to the DataExporter class to make ExceptionLogger loosely coupled with the low-level classes FileLogger and EventLogger. And by doing that, we are giving provision to DataExporter class to decide what kind of Logger should be called based on the exception that occurs.
public class ExceptionLogger
{
private ILogger _logger;
public ExceptionLogger(ILogger aLogger)
{
this._logger = aLogger;
}
public void LogException(Exception aException)
{
string strMessage = GetUserReadableMessage(aException);
this._logger.LogMessage(strMessage);
}
private string GetUserReadableMessage(Exception aException)
{
string strMessage = string.Empty;
//code to convert Exception's stack trace and message to user readable format.
....
....
return strMessage;
}
}
public class DataExporter
{
public void ExportDataFromFile()
{
ExceptionLogger _exceptionLogger;
try {
//code to export data from files to database.
}
catch(IOException ex)
{
_exceptionLogger = new ExceptionLogger(new DbLogger());
_exceptionLogger.LogException(ex);
}
catch(Exception ex)
{
_exceptionLogger = new ExceptionLogger(new FileLogger());
_exceptionLogger.LogException(ex);
}
}
}
We successfully removed the dependency on low-level classes. This ExceptionLogger doesn't depend on the FileLogger and EventLogger classes to log the stack trace. We no longer need to change the ExceptionLogger's code for the new logging functionality. We must create a new logging class that implements the ILogger interface and adds another catch block to the DataExporter class's ExportDataFromFile method.
public class EventLogger: ILogger
{
public void LogMessage(string aMessage)
{
//Code to write a message in system's event viewer.
}
}
And we need to add a condition in the DataExporter class as in the following:
public class DataExporter
{
public void ExportDataFromFile()
{
ExceptionLogger _exceptionLogger;
try {
//code to export data from files to database.
}
catch(IOException ex)
{
_exceptionLogger = new ExceptionLogger(new DbLogger());
_exceptionLogger.LogException(ex);
}
catch(SqlException ex)
{
_exceptionLogger = new ExceptionLogger(new EventLogger());
_exceptionLogger.LogException(ex);
}
catch(Exception ex)
{
_exceptionLogger = new ExceptionLogger(new FileLogger());
_exceptionLogger.LogException(ex);
}
}
}
Looks good. But we introduced the dependency here in the DataExporter class's catch blocks. So, someone must be responsible for providing the necessary objects to the ExceptionLogger to get the work done.
Let me explain it with a real-world example. Suppose we want to have a wooden chair with specific measurements and the kind of wood to be used to make that chair. Then we can't leave the decision-making on measures and the wood to the carpenter. Here his job is to make a chair based on our requirements with his tools, and we provide the specifications to him to make a good chair.
So what is the benefit we get from the design? Yes, we definitely have benefited from it. We need to modify the DataExporter and ExceptionLogger classes whenever we need to introduce a new logging functionality. But in the updated design, we need to add only another catch block for the new exception logging feature. We only need to properly understand the system, requirements, and environment and find areas where DIP should be followed. Coupling is not inherently evil. If you don't have some amount of coupling, your software will not do anything for you.
Conclusion
Great, we have gone through all five SOLID principles successfully. And we can conclude that using these principles, we can build an application with tidy, readable, and easily maintainable code.
Here you may have some doubts. Yes, about the quantity of code. Because of these principles, the code might become larger in our applications. But my dear friends, you need to compare it with the quality we get by following these principles. Hmm, but anyway, 27 lines are much fewer than 200 lines.
This is my little effort to share the uses of SOLID principles. I hope you enjoyed this article.
Images courtesy: https://lostechies.com/derickbailey/2009/02/11/solid-development-principles-in-motivational-pictures/
Thank you,
Damu

Kumar BhimsenPosted Oct 4, 2025, 7:35 AM
SOLID design principle https://youtu.be/iN9N5CjuuTo?si=NV0FCStos-H4ntJr
Aleksandar JasicPosted Sep 14, 2025, 5:45 PM
Great job! This is the best explanation of SOLID EVER! :)
Digen PatelPosted Aug 4, 2024, 5:21 AM
Now we implement IReadableSqlFile through the ReadOnlySqlFile class that reads only the text from read-only files. - This ReadOnlySqlFile is missing . Please check
RajPosted Mar 2, 2024, 5:15 AM
Good Explanation. But I have a question. In Open/Closed Principle, you have mentioned "Generally, we can do this by referring to abstractions for dependencies". Is this Abstraction concept you are referring?
Manjari ChandanaPosted Oct 18, 2023, 11:24 AM
Well explained... I could relate the explanation with real time scenarios. Thanks
Anil KumarPosted Oct 13, 2023, 5:06 PM
You tried in a best way to explain as simple as possible. Great Job.
Muhammad AsifPosted Sep 21, 2023, 10:30 AM
Great explanation! clearly deliver.
Ashish PandeyPosted Aug 22, 2023, 11:10 AM
Easy to understand and nice article. Thanks a lot.
Babsinki TeroPosted Jun 28, 2023, 10:46 AM
Public bool SendEmail(MailMessage message){ _smtpClient.Send(message); } I think this is void method not bool function. It should be. public void SendEmail(MailMessage message) { _smtpClient.Send(message); }
Babsinki TeroPosted Jun 28, 2023, 10:44 AM
There's a mistake location of your virtual modifier. You key-in public bool virtual ValidateEmail(string email) instead of public virtual bool ValidateEmail(string email).
Kunal DusanePosted Jun 15, 2023, 8:51 AM
Hi Damu, the explanation is really great! somehow I am not able to understand in dependency inversion principle why to have ExceptionLogger class if we can have ILogger as abstract class and have method to extract exception message defined in it. we can directly use the ILogger in DataExporter and use the DBLogger and FileLogger class. in this way, we wont have extra class. as we are already using class names in catch blocks.
Faisal Khan NaayabPosted May 24, 2023, 5:48 PM
The amazing article contains perfection of understanding of the concept.
rekha MahajanPosted Mar 13, 2023, 3:24 PM
In Open-closed Principle (OCP) how the objShape.Area() will decide which area method to call ? from rectangle or circle ??
Lawal AbdulateefPosted Feb 23, 2023, 7:56 PM
Thanks Damu
Rahul GuptaPosted Jan 17, 2023, 3:04 AM
A good explanation helps to understand the principle in a very simple way.
omer.javPosted Dec 15, 2022, 12:24 PM
Great writeup with very good real world examples.
Gururaj KLPosted Oct 27, 2022, 4:03 AM
Really Helpful, Thank you so much
ishara saminthaPosted Sep 25, 2022, 1:33 AM
Thank you and nice explanation..
Lin KaiPosted Jul 15, 2022, 3:55 AM
It's helpful. Thank you sir!
Abid ShaikPosted May 8, 2022, 5:50 PM
Good one Damu !! Thanks for taking time and writing it up ?? … Proud Telugu
Haitham HussienPosted Dec 8, 2021, 2:43 PM
It's a great work, Thank you for your effort.
Vishal JoshiPosted Aug 29, 2021, 9:22 AM
Thank you for sharing this very good article. it can help experienced developers too. :)
Oryza AnggaraPosted Aug 13, 2021, 8:34 AM
Thank you for sharing this, It's thorough and easier to digest :) ..Do you have any articles for the 3rd point of the Solution? ("3. Choosing correct Design Patterns to build the software based on its specifications.")
Adalat KhanPosted Jul 26, 2021, 1:34 PM
Good article thanks for sharing. The Example of the Interface Segregation Principle (ISP) part is outstanding. It is clear and easy to understand.
Ravi Kumar SirigineediPosted Jul 18, 2021, 6:08 PM
Great insight into SOLID principles. Bit Lengthy but useful.. Thank you very much...
Pranam BhatPosted Jun 27, 2021, 5:12 AM
Thanks for sharing!
Somasekara ReddyPosted Jun 10, 2021, 4:22 AM
Thanks. nice explnation
Rudhra SekaranPosted May 23, 2021, 3:08 PM
Very Clear & easy to understand !
Chukwuma OnuhPosted Apr 15, 2021, 11:34 PM
Thank you for this article
IMAD AYOUBPosted Apr 4, 2021, 7:03 PM
Excellent tutorial. Thanks a lot.
Bernard CzaińskiPosted Apr 2, 2021, 5:22 PM
Clear and fine. Congratulation.
ravi kumarPosted Mar 15, 2021, 11:40 AM
Good explanation thanks but have a doubt ,it is OSP or OCP i.e Open Closed Principle?
Joel ChucaPosted Mar 13, 2021, 12:49 AM
Thank you so much, this helped me to understand SOLID.
Eyayu TeferaPosted Feb 22, 2021, 7:32 PM
Thanks for the clear explanation
Mahi DPosted Jan 16, 2021, 10:46 AM
Very nicely explained with Examples ... Appreciated
Rohith MantenaPosted Nov 12, 2020, 2:40 AM
Very good examples
Shashank KadgePosted Oct 12, 2020, 7:22 AM
Nice work Damu. Do you have blog on Design patterns and Architecture (mvc, mvvp etc).
Naresh PandeyPosted Aug 29, 2020, 12:59 AM
Nice and easy..good explained with great examples..
IMAD AYOUBPosted Jun 29, 2020, 8:56 AM
Excellent article Damu. Thanks a lot.
Sabarinath APosted May 27, 2020, 6:23 AM
Nice and easily understandable
Yogesh KhurpePosted May 13, 2020, 4:14 AM
Nice Article..!!
Pappu KumarPosted Feb 14, 2020, 11:19 AM
Great Article and better Explanation.
Pruthwiraj JagadalePosted Jan 29, 2020, 10:17 AM
Very well explained
Rushi MehtaPosted Jan 28, 2020, 12:47 PM
Great Article
Parth MehtaPosted Sep 25, 2019, 12:14 AM
The example given for the SRP is not appropriate. Below class without refectoring follow the SRP. public class UserService { public void Register(string email, string password) { if (!ValidateEmail(email)) throw new ValidationException("Email is not an email"); var user = new User(email, password); SendEmail(new MailMessage("[email protected]", email) { Subject="HEllo foo" }); } public virtual bool ValidateEmail(string email) { return email.Contains("@"); } public bool SendEmail(MailMessage message) { _smtpClient.Send(message); } }
Anoop KPosted Sep 16, 2019, 12:27 PM
SOLID article !!! Principle explained very well
J PadiyathPosted Aug 7, 2019, 4:23 AM
Great Article! Understood every aspects of Solid Principles. Thanks.
Ilham NiyaPosted Jul 30, 2019, 6:45 AM
Thank you for this article
Steven CocoPosted Jul 26, 2019, 9:12 PM
Great article! The goals that are covered are spot-on; and the points are made clearly. The pictures really complement the points and the pitfalls well.
Majedur RahamanPosted Jul 1, 2019, 6:39 AM
Great article with example.
Niroj DahalPosted Jun 27, 2019, 1:03 PM
Nice explanation
Ravi PatelPosted Jun 21, 2019, 12:25 AM
Nice explanation thanks
Rajan MishraPosted Apr 29, 2019, 3:58 AM
Its a great article on SOLID. Do we have other design principles.
john sabharwalPosted Apr 18, 2019, 12:41 AM
Thank you so much..its pretty clear and easy to understand
somesh naiduPosted Mar 30, 2019, 6:24 PM
Simply super and Nice explanation.is there any performance impact as lines of code increasing.Please suggest on this.Thank you very much for your article.
MahmoudPosted Mar 21, 2019, 9:12 AM
Very good article, Thank you.
Ritu Rana Azure(PaaS,Stack,K8S),Dot NetPosted Feb 24, 2019, 3:02 PM
Nicely explained... please correct code in Open/Closed principle: if(obj is Rectangle) { objRectangle = (Rectangle)obj; area += obj.Height * obj.Width; } It should be : if(obj is Rectangle) { objRectangle = (Rectangle)obj; area += objRectangle.Height * objRectangle.Width; }
Hamid KhanPosted Nov 22, 2018, 1:13 AM
Member modified should be preceed the member type
Hamid KhanPosted Nov 22, 2018, 1:12 AM
Public bool virtual ValidateEmail(string email) { return email.Contains("@"); } public bool SendEmail(MailMessage message) { _smtpClient.Send(message); }
Prathamesh PurandarePosted Nov 11, 2018, 2:45 AM
Thanks Damu. Very useful.
Chinedu OparaPosted Oct 7, 2018, 9:37 PM
This was good, thank you.
אריאל הלויPosted Sep 25, 2018, 6:04 AM
Thank you!!
Pathakoti RajeshPosted Sep 19, 2018, 9:46 AM
Very clean and simple explanation, Thanks a lot brother
Madhu sudhanPosted Jun 7, 2018, 10:28 PM
Example taken for LSP is little complex. I reffered multiple sources to understand it. Rest all principle explained very well thanks for it !
Siva PrasadPosted Jun 5, 2018, 5:51 AM
Nice one with great explanation.
Nistrean DanielPosted Jun 3, 2018, 10:31 AM
Hi Damu. This is second article I read on this topic and I like it, buy I think your example of Liskov Substitution Principle is nor contradicting it, nor following it, because you don't inherit from SqlFile class, you don't have parent-child relationship anymore. This looks closer to ISP than LSP to me or I'm getting LSP wrong ?
Nilesh YadavPosted Apr 11, 2018, 9:52 AM
Nice explanation. Now my concept regarding SOLID principles is clear.
Kishor TalaPosted Apr 5, 2018, 1:52 PM
Very nice article. Example also good for better understanding.
Chaithanya DoddapaneniPosted Mar 21, 2018, 4:15 PM
Very Nice Article for everyone
Masthan RaoPosted Jan 28, 2018, 12:50 PM
Very good article Damu. Really helped me to get through the concepts of SOLID
Dennis ThomasPosted Jan 15, 2018, 5:27 AM
Good work Damo! It's a very nice article!
Hamid KhanPosted Dec 29, 2017, 10:47 AM
It is really very nice article for solid principle..........Thank you again............
Chinmaya DashPosted Dec 26, 2017, 10:19 AM
Very nice article loved it
Rahmad SuhermanPosted Dec 22, 2017, 6:00 AM
You should remove public modifier on LogMessage(string message) method. Modifier is not valid inside an interface
Rahmad SuhermanPosted Dec 22, 2017, 6:00 AM
You should remove public modifier on ILogger interface public interface ILogger { public void LogMessage(string message); }
Rahmad SuhermanPosted Dec 22, 2017, 6:00 AM
Public interface ILogger { public void LogMessage(string message); }
Rahmad SuhermanPosted Dec 22, 2017, 5:59 AM
Public interface ILogger { public void LogMessage(string message); }
Mitchell CookePosted Nov 25, 2017, 4:48 PM
This is easily the best explanation I've found online. Thanks.
Amol BankarPosted Sep 13, 2017, 12:52 AM
Super Damu....very well explained :)
Former memberPosted Aug 19, 2017, 9:19 AM
Good Article. You can also try most frequently asked SOLID Design Principle Interview Question and Answer On You Tube. Click the Below link => https://www.youtube.com/playlist?list=PLrFEJwFzIqtUoIcvC4ItOIs76l2GLURB5
ankur ranaPosted Jun 25, 2017, 9:44 AM
Your article is quite good. Just want to confirm one thing that Can we also create a Factory for logger classes i.e. for ILogger and classes which are implementing it (FileLogger/DbLogger etc.)
DevX GPosted Jun 15, 2017, 10:35 PM
You have declared non-static method in static class under Dependency Inversion section. This is not possible. public static class ExceptionLogger { public static void LogIntoFile(Exception aException) { FileLogger objFileLogger = new FileLogger(); objFileLogger.LogMessage(GetUserReadableMessage(aException)); } private string GetUserReadableMessage(Exception ex) { string strMessage = string. Empty; //code to convert Exception's stack trace and message to user readable format. .... .... return strMessage; } }
le gianguyenPosted Feb 25, 2017, 8:36 AM
Nice article. Thanks sir for sharing
vidit tyagiPosted Jan 13, 2017, 8:06 AM
Nice explanation sir. thanks for sharing.
Bijit PalPosted Dec 25, 2016, 3:05 PM
Great Article Damodhar. Thanks.
Suneetha PragadaPosted Dec 12, 2016, 5:17 PM
Very nice article with examples. Really appreciate your effort.
Naitik JaniPosted Dec 1, 2016, 2:41 AM
Great Article, Thanks For Sharing this !!
Satish Kumar VadlavalliPosted Nov 28, 2016, 4:33 AM
Nice share, keep up good work
Kanniyappan KrishPosted Nov 4, 2016, 8:24 AM
Nice article. way of explanation great. Thank you!
Shamim UddinPosted Sep 30, 2016, 3:58 AM
Nice
Chinedu OparaPosted Aug 24, 2016, 11:53 AM
Very nice article, well-written and explained. Thank you!
Hemant GuravPosted Jun 23, 2016, 5:48 AM
Very Nice explained
Damodara NaiduPosted May 26, 2016, 3:41 AM
Thank you Mudassar Chandle
Mudassar ChandlePosted May 23, 2016, 7:49 AM
Excellent. Well explained with the best examples. Really appreciate your effort.
Ankit KumarPosted May 17, 2016, 5:10 AM
Very Nice Article with good examples
Durga prasadPosted May 13, 2016, 11:17 AM
Great work damu.. really helpful.. Thanks
Nguyen HungPosted Mar 22, 2016, 2:36 AM
So good, Thanks so much
Rasik BapotraPosted Mar 18, 2016, 4:56 AM
Nice Article, keep it up.
Bhavik PatelPosted Jan 22, 2016, 10:52 AM
well explained
Ritesh AryaPosted Dec 28, 2015, 1:53 AM
NIce Article with good examples. Very helpful.
Banketeshvar NarayanPosted Nov 18, 2015, 4:23 AM
Nice Article
Harshad PansuriyaPosted Nov 17, 2015, 11:11 PM
Nice one
Nagaraj SPosted Nov 17, 2015, 10:19 AM
Hi..Damodhar Naidu. I believe its a tough topic to explain but you have presented it a very well manner. Thanks for sharing. May be the best article of the year.
Nishant MittalPosted Nov 17, 2015, 10:07 AM
Good One
Damodara NaiduPosted Nov 17, 2015, 4:00 AM
Thank you Sibeesh Venu
Sibeesh VenuPosted Nov 17, 2015, 3:58 AM
Nice Share
Rupali ShindePosted Nov 17, 2015, 1:10 AM
nice article
Ankit BansalPosted Nov 17, 2015, 12:45 AM
nice one..
Humayun Kabir MamunPosted Nov 17, 2015, 12:12 AM
Nice...
Former memberPosted Nov 16, 2015, 6:15 AM
Nice one.
Narasimha Reddy ChennupalliPosted Aug 4, 2015, 5:30 AM
nice article
Upendra Pratap ShahiPosted Jul 8, 2015, 12:46 AM
Very nice and well demonstrated Damodhar Naidu Sir...
Gaurav Kumar AroraPosted Dec 15, 2014, 8:09 AM
very nice, described contents
Sanjay GuptaPosted Dec 10, 2014, 1:37 AM
Well done! The best examples on SOLID principle. But "Liskov substitution Principle" example can be solved by "Interface Segregation Principle". However nice job. ;)
Deo CabralPosted Oct 11, 2014, 1:21 AM
thank you for the nice article
Jeetendra GundPosted Oct 9, 2014, 8:45 AM
nice article
Manju lata YadavPosted Oct 9, 2014, 8:32 AM
nice article..
Raju KatarePosted Oct 9, 2014, 7:42 AM
Nice explanation...
Dinesh BeniwalPosted Oct 9, 2014, 7:28 AM
Good start Damodhar, welcome to C# Corner.