> 技术文档 > 【C#补全计划:类和对象(六)—— 里氏替换原则】

【C#补全计划:类和对象(六)—— 里氏替换原则】


一、is关键字

1. 概念:判断一个对象是否为指定类的对象

2. 返回值:布尔值。对象是指定类型的对象为true,不是为false

3. 使用:

语法:对象 is 类名

using System;namespace IsAsAndObject{ class Program { static void Main(string[] args) { // is关键字的使用 Ragdoll ragdoll = new Ragdoll(); bool isCat = ragdoll is Animal; // 使用is关键字检查ragdoll是否是Cat类型 bool isDog = ragdoll is Dog; // 检查ragdoll是否是Dog类型 Console.WriteLine(\"ragdoll是猫:\" + isCat); // 输出:True Console.WriteLine(\"ragdoll是狗:\" + isDog); // 输出:False } } class Animal { public string Name { get; set; } public void animalSpeak() { Console.WriteLine(\"Animal speaks\"); } } class Cat : Animal { public void catSpeak() { Console.WriteLine(\"Cat meows\"); } } class Dog : Animal { public void dogSpeak() { Console.WriteLine(\"Dog barks\"); } } class Ragdoll : Cat { public void ragdollSpeak() { Console.WriteLine(\"Ragdoll purrs\"); } }}

运行结果如下:

二、as关键字

1. 概念:将一个对象转换为指定类的对象

2. 返回值:指定类型的对象。对象转换成功返回指定类型对象,失败返回null

3. 使用:

语法:对象 as 类名

using System;namespace IsAsAndObject{ class Program { static void Main(string[] args) { // is关键字的使用 Ragdoll ragdoll = new Ragdoll(); bool isCat = ragdoll is Animal; // 使用is关键字检查ragdoll是否是Cat类型 bool isDog = ragdoll is Dog; // 检查ragdoll是否是Dog类型 Console.WriteLine(\"ragdoll是猫:\" + isCat); // 输出:True Console.WriteLine(\"ragdoll是狗:\" + isDog); // 输出:False // as关键字的使用 Animal dog = new Dog(); // 创建了一个Dog类实例,但将其引用赋给Animal类型的变量。编译时是Animal类型,运行时是Dog类型 // dog.dogSpeak() // 编译错误:Animal类没有dogSpeak方法 (dog as Dog).dogSpeak(); // 使用as关键字进行类型转换,调用Dog类的方法,编译成功 } } class Animal { public string Name { get; set; } public void animalSpeak() { Console.WriteLine(\"Animal speaks\"); } } class Cat : Animal { public void catSpeak() { Console.WriteLine(\"Cat meows\"); } } class Dog : Animal { public void dogSpeak() { Console.WriteLine(\"Dog barks\"); } } class Ragdoll : Cat { public void ragdollSpeak() { Console.WriteLine(\"Ragdoll purrs\"); } }}

运行结果如下:

三、里氏替换原则

        里氏替换原则是面向对象七大原则中最重要的原则

1. 概念:任何父类出现的地方,子类都可以替代

2. 要求:

  • 子类必须完全实现父类约定

  • 子类不能破坏父类的行为

  • 子类可以扩展但不能修改核心行为

3. 语法表现:父类容器装载子类对象,因为子类对象包含了父类中的所有内容

4. 作用:方便进行对象存储和管理

5. 示例:

using System;namespace IsAsAndObject{ class Program { static void Main(string[] args) { // is关键字的使用 Ragdoll ragdoll = new Ragdoll(); bool isCat = ragdoll is Animal; // 使用is关键字检查ragdoll是否是Cat类型 bool isDog = ragdoll is Dog; // 检查ragdoll是否是Dog类型 Console.WriteLine(\"ragdoll是猫:\" + isCat); // 输出:True Console.WriteLine(\"ragdoll是狗:\" + isDog); // 输出:False // as关键字的使用 Animal dog = new Dog(); // 创建了一个Dog类实例,但将其引用赋给Animal类型的变量。编译时是Animal类型,运行时是Dog类型 // dog.dogSpeak() // 编译错误:Animal类没有dogSpeak方法 (dog as Dog).dogSpeak(); // 使用as关键字进行类型转换,调用Dog类的方法,编译成功 // 里氏替换原则示例: Console.WriteLine(\"里氏替换原则示例:\"); Animal[] animals = new Animal[] { new Animal(\"小云\"), new Cat(\"小灰\"), new Dog(\"小黑\"), new Ragdoll(\"小白\") }; foreach(Animal a in animals) { Console.WriteLine(a.Name + \":\"); a.animalSpeak(); // 调用Animal类的方法,所有子类都可以调用 if (a is Cat) { // 使用is关键字检查是否是Cat类型  if(a is Ragdoll r) { // 进一步检查是否是Ragdoll类型 r.ragdollSpeak(); // 调用Ragdoll类的方法 continue;  }  (a as Cat).catSpeak(); // 调用Cat类的方法 } else if (a is Dog) {// 使用is关键字检查是否是Dog类型  (a as Dog).dogSpeak(); // 调用Dog类的方法 } } } } class Animal { public string Name { get; set; } public Animal() {} public Animal(string name) { Name = name; } public void animalSpeak() { Console.WriteLine(\"Animal speaks\"); } } class Cat : Animal { public Cat() {} public Cat(string name) : base(name) {} public void catSpeak() { Console.WriteLine(\"Cat meows\"); } } class Dog : Animal { public Dog() {} public Dog(string name) : base(name) {} public void dogSpeak() { Console.WriteLine(\"Dog barks\"); } } class Ragdoll : Cat { public Ragdoll() {} public Ragdoll(string name) : base(name) {} public void ragdollSpeak() { Console.WriteLine(\"Ragdoll purrs\"); } }}

运行结果如下:

四、万类之父:Object 

1. 关键字:object

2. 概念:object是所有类的基类,他是一个类(引用类型)

3. 作用:

        (1)可以利用里氏替换原则,用object容器装所有对象

        (2)可以用来表示不确定的类型,作为函数参数中的类型

4. 使用:

using System;namespace IsAsAndObject{ class Program { static void Main(string[] args) { // is关键字的使用 Ragdoll ragdoll = new Ragdoll(); bool isCat = ragdoll is Animal; // 使用is关键字检查ragdoll是否是Cat类型 bool isDog = ragdoll is Dog; // 检查ragdoll是否是Dog类型 Console.WriteLine(\"ragdoll是猫:\" + isCat); // 输出:True Console.WriteLine(\"ragdoll是狗:\" + isDog); // 输出:False // as关键字的使用 Animal dog = new Dog(); // 创建了一个Dog类实例,但将其引用赋给Animal类型的变量。编译时是Animal类型,运行时是Dog类型 // dog.dogSpeak() // 编译错误:Animal类没有dogSpeak方法 (dog as Dog).dogSpeak(); // 使用as关键字进行类型转换,调用Dog类的方法,编译成功 // 里氏替换原则示例: Console.WriteLine(\"里氏替换原则示例:\"); Animal[] animals = new Animal[] { new Animal(\"小云\"), new Cat(\"小灰\"), new Dog(\"小黑\"), new Ragdoll(\"小白\") }; foreach(Animal a in animals) { Console.WriteLine(a.Name + \":\"); a.animalSpeak(); // 调用Animal类的方法,所有子类都可以调用 if (a is Cat) { // 使用is关键字检查是否是Cat类型  if(a is Ragdoll r) { // 进一步检查是否是Ragdoll类型 r.ragdollSpeak(); // 调用Ragdoll类的方法 continue;  }  (a as Cat).catSpeak(); // 调用Cat类的方法 } else if (a is Dog) {// 使用is关键字检查是否是Dog类型  (a as Dog).dogSpeak(); // 调用Dog类的方法 } } // 万类之父:Object的使用 // 引用类型 object obj1 = new Ragdoll(\"大白\"); if(obj1 is Ragdoll) (obj1 as Ragdoll).ragdollSpeak(); // 使用as关键字转换时,如果转换失败,结果为null // 值类型 object obj2 = 100; int i = (int)obj2; // 强制类型转换:将object类型转换为int类型 // 注意:如果obj2不是int类型,这里会抛出InvalidCastException异常 // 数组类型 object obj3 = new int[10]; int[] arr1 = obj3 as int[]; // 使用as关键字进行类型转换 int[] arr2 = (int[])obj3; // 强制类型转换 // string类型 object obj4 = \"Hello, World!\"; string str1 = obj4 as string; // 使用as关键字进行类型转换 string str2 = (string)obj4; // 强制类型转换 string str3 = obj4.ToString(); // 调用ToString方法转换 string str4 = obj4 + \"\"; // 使用字符串拼接转换 } } class Animal { public string Name { get; set; } public Animal() {} public Animal(string name) { Name = name; } public void animalSpeak() { Console.WriteLine(\"Animal speaks\"); } } class Cat : Animal { public Cat() {} public Cat(string name) : base(name) {} public void catSpeak() { Console.WriteLine(\"Cat meows\"); } } class Dog : Animal { public Dog() {} public Dog(string name) : base(name) {} public void dogSpeak() { Console.WriteLine(\"Dog barks\"); } } class Ragdoll : Cat { public Ragdoll() {} public Ragdoll(string name) : base(name) {} public void ragdollSpeak() { Console.WriteLine(\"Ragdoll purrs\"); } }}

五、装箱和拆箱

1. 概念:

        (1)用object存储值类型(装箱)

        (2)将object转换为值类型(拆箱)

2. 装箱:

        (1)把值类型的变量用引用类型存储

        (2)栈内存会迁移到堆内存中

3. 拆箱

        (1)把引用类型存储的值类型取出来

        (2)堆内存会迁移到栈内存中

4. 优点:不确定类型时可以方便参数的存储和传递

5. 缺点:存在内存迁移,增加性能消耗

using System;namespace IsAsAndObject{ class Program { static void Main(string[] args) { // is关键字的使用 Ragdoll ragdoll = new Ragdoll(); bool isCat = ragdoll is Animal; // 使用is关键字检查ragdoll是否是Cat类型 bool isDog = ragdoll is Dog; // 检查ragdoll是否是Dog类型 Console.WriteLine(\"ragdoll是猫:\" + isCat); // 输出:True Console.WriteLine(\"ragdoll是狗:\" + isDog); // 输出:False // as关键字的使用 Animal dog = new Dog(); // 创建了一个Dog类实例,但将其引用赋给Animal类型的变量。编译时是Animal类型,运行时是Dog类型 // dog.dogSpeak() // 编译错误:Animal类没有dogSpeak方法 (dog as Dog).dogSpeak(); // 使用as关键字进行类型转换,调用Dog类的方法,编译成功 // 里氏替换原则示例: Console.WriteLine(\"里氏替换原则示例:\"); Animal[] animals = new Animal[] { new Animal(\"小云\"), new Cat(\"小灰\"), new Dog(\"小黑\"), new Ragdoll(\"小白\") }; foreach(Animal a in animals) { Console.WriteLine(a.Name + \":\"); a.animalSpeak(); // 调用Animal类的方法,所有子类都可以调用 if (a is Cat) { // 使用is关键字检查是否是Cat类型  if(a is Ragdoll r) { // 进一步检查是否是Ragdoll类型 r.ragdollSpeak(); // 调用Ragdoll类的方法 continue;  }  (a as Cat).catSpeak(); // 调用Cat类的方法 } else if (a is Dog) {// 使用is关键字检查是否是Dog类型  (a as Dog).dogSpeak(); // 调用Dog类的方法 } } // 万类之父:Object的使用 // 引用类型 object obj1 = new Ragdoll(\"大白\"); if(obj1 is Ragdoll) (obj1 as Ragdoll).ragdollSpeak(); // 使用as关键字转换时,如果转换失败,结果为null // 值类型 object obj2 = 100; int i = (int)obj2; // 强制类型转换:将object类型转换为int类型 // 注意:如果obj2不是int类型,这里会抛出InvalidCastException异常 // 数组类型 object obj3 = new int[10]; int[] arr1 = obj3 as int[]; // 使用as关键字进行类型转换 int[] arr2 = (int[])obj3; // 强制类型转换 // string类型 object obj4 = \"Hello, World!\"; string str1 = obj4 as string; // 使用as关键字进行类型转换 string str2 = (string)obj4; // 强制类型转换 string str3 = obj4.ToString(); // 调用ToString方法转换 string str4 = obj4 + \"\"; // 使用字符串拼接转换 // 装箱和拆箱 Console.WriteLine(\"装箱和拆箱示例:\"); Console.WriteLine(\"sum = \" + Sum(1, 2.0, 3.0f, \"4\", new Dog())); // 装箱操作:将不确定类型的值转换为object类型 } static float Sum(params object[] objects) { float sum = 0; foreach (object o in objects) // 拆箱操作:将object类型的值转换为具体类型 { if(o is int) sum += (int)o; if(o is float) sum += (float)o; if(o is double) sum += (float)(double)o; if(o is string) sum += float.TryParse((string)o, out float result) ? result : 0f; if(o is Animal) continue; } return sum; } } class Animal { public string Name { get; set; } public Animal() {} public Animal(string name) { Name = name; } public void animalSpeak() { Console.WriteLine(\"Animal speaks\"); } } class Cat : Animal { public Cat() {} public Cat(string name) : base(name) {} public void catSpeak() { Console.WriteLine(\"Cat meows\"); } } class Dog : Animal { public Dog() {} public Dog(string name) : base(name) {} public void dogSpeak() { Console.WriteLine(\"Dog barks\"); } } class Ragdoll : Cat { public Ragdoll() {} public Ragdoll(string name) : base(name) {} public void ragdollSpeak() { Console.WriteLine(\"Ragdoll purrs\"); } }}

运行结果如下:

        今天的学习就到这里了。感谢阅读。

        再见!