子类型必须能够替换它们的基类性

如果对每一个类型为S的对象o1, 都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都替换成o2时, 程序P的行为没有变化, 那么类型s是类型T的子类型.

所有引用基类的地方必须能透明地使用其子类的对象.

里氏替换原则是实现开闭原则的重要方式之一, 由于使用基类对象的地方都可以使用子类对象, 因此在程序中尽量使用基类类型来对对象进行定义, 而在运行时再确定其子类类型, 用子类对象来替换父类对象.

// 里氏替换原则实例001
namespace 里氏替换原则实例001
{
    public abstract class AbstractGun
    {
        public abstract void Shoot();
    }

    public class HandGun : AbstractGun
    {
        public override void Shoot()
        {
            Console.WriteLine("手枪射击");
        }
    }

    public class Rifle : AbstractGun
    {
        public override void Shoot()
        {
            Console.WriteLine("步枪射击");
        }
    }

    public class MachineGun : AbstractGun
    {
        public override void Shoot()
        {
            Console.WriteLine("机枪射击");
        }
    }

    public class Soldier
    {
        public void KillEnemy(AbstractGun gun)
        {
            Console.Write("战士使用");
            gun.Shoot();
        }
    }

    public class ToyGun : AbstractGun
    {
        public override void Shoot()
        {
            Console.WriteLine("玩具枪");
        }
    }

    public class G3 : Rifle
    {
        public void ZoomOut()
        {
            Console.WriteLine("望远镜查看敌人");
        }

        public void Shoot()
        {
            Console.WriteLine("G3射击");
        }
    }

    public class Snipper
    {
        public void KillEnemy(G3 g3)
        {
            g3.ZoomOut();
            g3.Shoot();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Soldier hero = new Soldier();
            hero.KillEnemy(new ToyGun());
            hero.KillEnemy(new Rifle());
            hero.KillEnemy(new HandGun());

            Snipper snipper01 = new Snipper();
            snipper01.KillEnemy(new G3());

            // 父类代替子类可能会造成系统不稳定 不推荐
            //Snipper snipper02 = new Snipper();
            //Rifle rifle = new Rifle();
            //snipper02.KillEnemy((G3)rifle);

        }
    }
}
// 里氏替换原则实例002
namespace 里氏替换原则实例002
{
    public class A
    {
        public virtual int Func(int x,int y)
        {
            return x * y;
        }
    }

    public class B : A
    {
        public override int Func(int x, int y)
        {
            return x - y;   // 违法了里氏替换原则, 直接重写了父类的Func虚拟方法, 引用父类的地方并不能透明的使用子类的对象.
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            B a = new B();
            Console.WriteLine("10 + 5 = " + a.Func(10, 5));
            
            A b = new B();
            Console.WriteLine("10 + 5 = " + b.Func(10, 5));
        }
    }
}
namespace 里氏替换原则实例003
{
    public class A
    {
        public int Func(int x,int y)
        {
            return x + y;
        }
    }

    public class B : A
    {
        public int Func1(int x,int y)
        {
            return x - y;   // 可以重新别的方法
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            B b = new B();
            Console.WriteLine("10 - 5 = " + b.Func1(10 ,5));

        }
    }
}
// 里氏替换原则实例004
namespace 里氏替换原则实例004
{
    class Rectangle
    {
        int height, width;
        public int GetWidth()
        {
            return width;
        }

        public void SetWidth(int width)
        {
            this.width = width;
        }

        public int GetHeight()
        {
            return height;
        }

        public void SetHeight(int height)
        {
            this.height = height;
        }
    }

    class Square : Rectangle
    {
        int size;

        public int GetWidht()
        {
            return size;
        }

        public void SetWidth(int width)
        {
            this.size = width;
        }

        public int GetHeight()
        {
            return size;
        }

        public void SetHeight(int height)
        {
            this.size = height;
        }

        public int GetSize()
        {
            return size;
        }

        public void SetSize(int size)
        {
            this.size = size;
        }
    }

    class Program
    {
        // 调整
        public static void TestRec(Rectangle rec)
        {
            int i = 0;
            while (rec.GetWidth() <= rec.GetHeight())
            {
                rec.SetWidth(rec.GetWidth() + 1);
                Console.WriteLine("循环次数: " + i++);
            }
        }

        static void Main(string[] args)
        {
            Rectangle rec = new Square();

            rec.SetWidth(5);
            rec.SetHeight(1000);

            TestRec(rec);

        }
    }
}

Q.E.D.