Over a million developers have joined DZone.

Liskov Substitution Principle in C#

DZone's Guide to

Liskov Substitution Principle in C#

Explaining the Liskov substitution principle to properly manage class heirarchy in C#.

· Web Dev Zone
Free Resource

Learn how to build modern digital experience apps with Crafter CMS. Download this eBook now. Brought to you in partnership with Crafter Software

The Liskov substitution principle (LSP) is a collection of guidelines for creating inheritance hierarchies in which a client can reliably use any class or subclass without compromising the expected behavior. If the rules of the LSP are not followed, an extension to a class hierarchy—that is, a new subclass—might necessitate changes to any client of the base class or interface. If the LSP is followed, clients can remain unaware of changes to the class hierarchy. As long as there are no changes to the interface, there should be no reason to change any existing code. The LSP, therefore, helps to enforce both the open/closed principle and the single responsibility principle.

The definition of the LSP by prominent computer scientist Barbara Liskov is a bit dry, so it requires further explanation. Here is the official definition:

Barbara Liskov: If S is a subtype of T, then objects of type T may be replaced with objects of type S, without breaking the program.

There are three code ingredients relating to the LSP:

  1. Base type – The type (T) that clients have reference to. Clients call various methods, any of which can be overridden—or partially specialized—by the subtype.

  2. Subtype – Any one of a possible family of classes (S) that inherit from the base type (T). Clients should not know which specific subtype they are calling, nor should they need to. The client should behave the same regardless of the subtype instance that it is given. 

  3. Context – The way in which the client interacts with the subtype. If the client doesn’t interact with a subtype, the LSP can neither be honored nor contravened.

LSP Rules

There are several “rules” that must be followed for LSP compliance. These rules can be split into two categories: contract rules (relating to the expectations of classes) and variance rules (relating to the types that can be substituted in code).What are contract rules? These rules relate to the contract of the supertype and the restrictions placed on the contracts that can be added to the subtype. 

  • Preconditions cannot be strengthened in a subtype.

  • Postconditions cannot be weakened in a subtype. 

  • Invariants — conditions that must remain true — of the supertype must be preserved in a subtype.

To understand the contract rules, you should first understand the concept of contracts and then explore what you can do to ensure that you follow these rules when creating subtypes. What are the variance rules?

These rules relate to the variance of arguments and return types.

  • There must be contravariance of the method arguments in the subtype.

  • There must be covariance of the return types in the subtype.

  • No new exceptions can be thrown by the subtype unless they are part of the existing exception hierarchy.

The concept of type variance in the languages of the Common Language Runtime (CLR) of the Microsoft .NET Framework is limited to generic types and delegates. However, variance in these scenarios is well worth exploring and will equip you with the requisite knowledge to write code that is LSP compliant for variance.

Crafter is a modern CMS platform for building modern websites and content-rich digital experiences. Download this eBook now. Brought to you in partnership with Crafter Software.

c# ,liskov substitution principle ,.net

Published at DZone with permission of Amir Ahani, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.


Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.


{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}