The object of a derived class should be able to replace/substitute an object of the base class without bringing any errors in the system or modifying the behavior of the base class.

A child class objects should be able to replace parent class objects without compromising application integrity. So basically a child class should be able to do anything a parent class can do.

The Famous Rectangle-Square Example :

Rectangle as a base class with Square class inherits from it. In the square class, we will over ride the be behavior of setters to enforce the length and width have same value

Class Rectangle 
{
	public virtual float Height { get; set; }
    public virtual float Width { get; set; }
    public virtual float Area 
    {
    	get {return Height * Width;
    }
}
Class Square : Rectangle
{
	private float _height;
    private float _width;
    
    public overide float Height
    {
    	get 
        {
       		return _height;
        }
        set
        {
        	_height = value;
            _width = value;
        }
    }
    public overide float Width
    {
    	get 
        {
        	return _width;
        }
        set
        {
        	_height = value;
            _width = value;
        }
    }
}

Now , lets write two tests to check LSP

[TestClass]
Public Class TestLSP
{
	[TestMethod]
    public void TestWithRectangle()
    {
    	Rectangle ret = new Rectangle();
        ret.Height = 10;
        ret.Width = 20;
        
        Assert.AreEqual(200, ret.Area);
    }
    
    [TestMethod]
    public void TestWithSquare()
    {
    	Rectangle sq = new Square()
        
        sq.Heigth = 10;
        sq.Width = 20;
        Assert.AreEqual(200, sq.Area); //This test will fail. Area equals 400.
    }
}

At first this code seems fine however it violets LSP, the Area method should give the same area in both the cases. The behavior of subclass (Square) has changed, thus the sub-class is not a substitute of the base class.

Now lets upgrade this solution by introducing Shape abstract class

abstract Class Shape
{
	public abstract float Area {get; }
}

class Rectangle : Shape
{
	public float Heigth { get; set; }
	public float Width { get; set; }
	public override float Area	
	{
		get { return Heigth * Width; }	
	}
}
class Square : Shape
{	
	public float Edge { get; set; }
	public override float Area
	{
		get { return Edge * Edge; }
	}
}

Now this code says both the Rectangle and the Square class are Shapes, which is true and it follows the LSP.