【从零开始入门unity游戏开发之——C#篇23】C#面向对象继承——`as`类型转化和`is`类型检查、向上转型和向下转型、里氏替换原则(LSP)

server/2024/12/23 3:57:30/

文章目录

  • 一、`as`类型转化和`is`类型检查
    • 1、`as` 关键字
      • 使用场景:
      • 语法:
      • 示例:
      • 特点:
    • 2、`is` 关键字
      • 使用场景:
      • 语法:
      • 示例:
      • 特点:
    • 3、总结
  • 二、向上转型和向下转型
    • 1、向上转型
      • 示例:
    • 2、向下转型
      • 示例:
    • 3、向下转型的安全性
      • 使用 `is` 操作符:
      • 使用 `as` 操作符:
    • 4、总结
  • 三、里氏替换原则
    • 1、什么是里氏替换原则
    • 2、**为什么要遵循里氏替换原则?**
      • 2.1 **程序更可靠**
      • 2.2 **更容易维护**
      • 2.3 **支持扩展**
    • 3、**举个例子**
    • 4、**总结**
  • 专栏推荐
  • 完结

一、as类型转化和is类型检查

在C#中,asis是两种用于类型转换和类型检查的关键字,它们的作用和用法有所不同。下面是这两个关键字的详细介绍:

1、as 关键字

as 关键字用于进行类型转换,通常用于将一个对象转换为指定的类型。如果转换成功,返回转换后的对象;如果转换失败,返回 null

使用场景:

  • as 用于安全的类型转换,可以避免抛出异常。
  • 它通常用于引用类型的转换(包括接口转换),而不适用于值类型(如 intdouble 等)。

语法:

object obj = someObject;
SomeClass objAsClass = obj as SomeClass;

如果 objSomeClass 类型的实例,objAsClass 将引用该实例;否则,它将是 null

示例:

class Animal { }
class Dog : Animal { }Animal animal = new Dog();
Dog dog = animal as Dog;  // 成功转换,dog 不为 nullobject obj = "Hello";
string str = obj as string;  // 成功转换,str 为 "Hello"int? num = obj as int?;  // 转换失败,num 为 null

特点:

  • 如果转换失败,as 不会抛出异常,而是返回 null
  • 适用于引用类型和可空值类型(Nullable<T>)。

2、is 关键字

is 关键字用于检查对象是否可以转换为指定的类型,返回一个布尔值(truefalse)。如果对象是指定类型的实例,返回 true,否则返回 false

使用场景:

  • is 常用于类型检查,在执行类型转换之前验证对象是否符合预期类型。
  • 适用于所有类型(值类型引用类型)。

语法:

if (obj is SomeClass) {// obj 是 SomeClass 类型
}

示例:

object obj = "Hello";if (obj is string) {Console.WriteLine("obj 是 string 类型" );
} else {Console.WriteLine("obj 不是 string 类型");
}if (obj is int) {Console.WriteLine("obj 是 int 类型");
} else {Console.WriteLine("obj 不是 int 类型");
}

在C# 7.0及更高版本中,is 关键字还可以在检查类型的同时进行类型转换。例如:

object obj = "Hello";
if (obj is string str) {Console.WriteLine($"字符串值: {str}");
}

特点:

  • is 在检查类型时,不会抛出异常。
  • 如果使用 is 进行类型检查后,成功匹配的类型可以直接赋值给变量(如上面的 str),避免了显式的转换。

3、总结

  • 使用 as 来进行类型转换时,它不会抛出异常。如果转换成功,它会返回转换后的对象;如果转换失败,它会返回 null
  • 使用 is 来进行类型检查时,它会返回一个布尔值,可以在检查通过时直接进行类型转换,避免了额外的类型转换步骤。

这两者通常配合使用,以确保类型转换的安全性和准确性。


二、向上转型和向下转型

在 C# 中,向上转型向下转型是涉及类型转换的两个概念,通常与类的继承和多态性相关。

1、向上转型

向上转型是指将一个派生类对象转换为其基类类型。由于派生类继承了基类的所有成员(字段、属性、方法等),因此,派生类对象可以被当作基类对象来使用。

向上转型是安全的,通常是不需要显式的类型转换,因为编译器会自动进行转换。

示例:

class Animal
{public void Speak(){Console.WriteLine("Animal speaks");}
}class Dog : Animal
{public void Bark(){Console.WriteLine("Dog barks");}
}class Program
{static void Main(){Dog dog = new Dog();// 向上转型Animal animal = dog; // Dog 转换为 Animalanimal.Speak(); // Animal 的方法// animal.Bark(); // 编译错误,因为 animal 是 Animal 类型,不能调用 Dog 的方法}
}

在这个例子中,dog 对象被向上转型为 Animal 类型。通过 animal 变量,我们只能访问 Animal 类中的成员,而无法访问 Dog 类特有的方法(如 Bark())。

2、向下转型

向下转型是指将一个基类类型的对象转换为派生类类型。向下转型需要显式进行,因为基类类型的变量可能包含多个不同的派生类实例,而编译器无法确定转换的安全性。

向下转型通常会涉及到检查运行时类型,因为如果对象的实际类型不是目标类型的实例,强制转换会引发运行时异常。

示例:

class Animal
{public void Speak(){Console.WriteLine("Animal speaks");}
}class Dog : Animal
{public void Bark(){Console.WriteLine("Dog barks");}
}class Program
{static void Main(){Animal animal = new Dog(); // 向上转型Dog dog = (Dog)animal; // 向下转型,显式转换dog.Bark(); // 可以调用 Dog 的方法// 以下代码会抛出 InvalidCastException 异常// Animal animal2 = new Animal();// Dog dog2 = (Dog)animal2; // 异常,因为 animal2 实际上不是 Dog 类型}
}

3、向下转型的安全性

为了避免 InvalidCastException 异常,可以使用 isas 操作符进行安全的类型转换。

使用 is 操作符:

is 用于检查对象是否可以转换为指定的类型。如果可以,则返回 true,否则返回 false

Animal animal = new Dog();
if (animal is Dog dog)
{dog.Bark(); // 安全地调用 Bark()
}
else
{Console.WriteLine("animal 不是 Dog 类型");
}

使用 as 操作符:

as 操作符会尝试将对象转换为指定的类型。如果不能转换,则返回 null,而不会抛出异常。
先判断,在转换。(它比传统的强制转换相对来说要安全一点,因为传统的强制转换, 一旦转换失败的话,程序就会崩溃,那么使用as关键字,如果转换不成功,就转换成空类型)

Animal animal = new Dog();
Dog dog = animal as Dog; // 如果 animal 不是 Dog 类型,则 dog 为 null
if (dog != null)
{dog.Bark(); // 安全地调用 Bark()
}
else
{Console.WriteLine("animal 不是 Dog 类型");
}

4、总结

  • 向上转型:将派生类对象转换为基类类型,编译器自动进行转换,通常是安全的。
  • 向下转型:将基类对象转换为派生类类型,需要显式转换,可能会抛出 InvalidCastException,因此需要使用 isas 进行安全检查。

三、里氏替换原则

里氏替换原则(Liskov Substitution Principle,LSP)是面向对象设计中的五大原则之一,它在设计和实现继承体系时起着至关重要的作用。遵循里氏替换原则能确保系统的稳定性、扩展性和可维护性。

1、什么是里氏替换原则

里氏替换原则是面向对象编程中一个非常重要的设计原则,它的意思是:

如果一个类是另一个类的子类,那么在程序中可以用子类的实例来替换父类的实例,而且程序的行为不会改变。

简单来说,里氏替换原则要求:你可以用子类(从父类继承的类)替换掉父类,而不会让程序出错

举个简单的例子:

假设你有一个父类 动物,有一个方法 叫()。然后你有一个子类 ,它也有 叫() 方法。当你把一个 对象传给需要 动物 对象的函数时,这个函数依然能正常工作,不会因为传入了 而出错。

2、为什么要遵循里氏替换原则

2.1 程序更可靠

如果子类没有遵循里氏替换原则,程序可能会因为传入子类对象而出错。遵循这个原则,可以确保子类对象可以正常替代父类对象,程序不会崩溃或出现奇怪的行为。

2.2 更容易维护

如果每个子类都能正确替换父类,程序的结构更简单,修改一个部分时不会影响到其他地方,代码更加稳定。例如,你可以在不改变其他代码的情况下,换成不同的子类,程序依然能正常工作。

2.3 支持扩展

当你遵循里氏替换原则时,未来增加新的子类(比如 继承 动物)也会很容易,新的子类会和旧的代码兼容,不会引起问题。

3、举个例子

假设有一个程序需要打印出所有动物叫的声音:

class Animal {public virtual void MakeSound() {Console.WriteLine("Some sound");}
}class Dog : Animal {public override void MakeSound() {Console.WriteLine("Bark");}
}class Cat : Animal {public override void MakeSound() {Console.WriteLine("Meow");}
}void PrintSound(Animal animal) {animal.MakeSound();
}

在这个例子里,DogCat 都继承自 Animal,并且实现了 MakeSound() 方法。你可以把 DogCat 传给 PrintSound(),程序依然会正常工作。

如果里氏替换原则被破坏,比如 Dog 类修改了父类的行为,导致无法在 PrintSound() 中正常工作,那就说明没有遵循这个原则,程序可能会出错或表现得不对。

4、总结

  • 里氏替换原则确保子类可以无缝替换父类而不破坏程序行为。
  • 它让你的代码更稳定、容易维护和扩展。
  • 你可以放心地使用不同的子类,而不必担心它们会影响到程序的其他部分。

专栏推荐

地址
【从零开始入门unity游戏开发之——C#篇】
【从零开始入门unity游戏开发之——unity篇】
【制作100个Unity游戏】
【推荐100个unity插件】
【实现100个unity特效】
unity框架开发】

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述


http://www.ppmy.cn/server/152398.html

相关文章

Java设计模式实战:策略模式、工厂模式、模板模式组合使用

Java设计模式实战&#xff1a;策略模式、工厂模式、模板模式组合使用 在软件开发中&#xff0c;设计模式是解决特定问题的成熟模板。它们可以帮助我们写出更灵活、更可维护的代码。本文将通过一个充电场景为例&#xff0c;展示如何将策略模式&#xff08;Strategy Pattern&…

oracle常用语句

目录 一.连接数据库SQL*Plus 连接本地连接远程连接使用操作系统认证 二.管理数据库启动数据库关闭数据库 三.数据字典和视图视图&#xff1a;1.数据库基础信息视图V$DATABASEV$INSTANCEV$VERSION 2.用户和权限管理视图DBA_USERSDBA_ROLE_PRIVSDBA_SYS_PRIVSDBA_TAB_PRIVS 3.表空…

线程和进程、作业的区别

线程和进程、作业的区别 作业&#xff08;任务&#xff09;有多个进程&#xff0c;进程有多个线程 进程&#xff08;Process&#xff09;&#xff1a; 进程是程序的一次执行过程&#xff0c;是操作系统进行资源分配和调度的基本单位。 每个进程都有独立的内存空间&#xff0c…

速通Python 第二节

一、动态类型特性 在 Python 中 , 一个变量是什么类型 , 是可以在 " 程序运行 " 过程中发生变化的 . 这个特性称为 " 动态类型 " a 10 print(type(a)) a hello print(type(a) 在程序执行过程中, a 的类型刚开始是 int, 后面变成了 str. C/Java 这…

opencv-python的简单练习

文章目录 识别信号灯识别图案并且标记面积和周长 识别信号灯 需要识别交通信号灯的颜色&#xff08;红、黄、绿&#xff09;。请设计一个简化的流程&#xff0c;说明如何使用OpenCV来识别交通信号灯的颜色。 思路分析‌&#xff1a; 1.读取包含交通信号灯的图像。 2.转换图像到…

Sigrity System Explorer Snip Via Pattern From Layout模式从其它设计中截取过孔模型和仿真分析操作指导

Sigrity System Explorer Snip Via Pattern From Layout模式从其它设计中截取过孔模型和仿真分析操作指导 Sigrity System Explorer Snip Via Pattern From Layout模式支持从其它设计中截取过孔模型用于仿真分析,同样以差分模板为例 具体操作如下 双击打开System Explorer软件…

MySQL结构的主要组成

MySQL 架构主要由以下几个部分组成&#xff1a; 一、连接层 当客户端连接到 MySQL 服务器时&#xff0c;连接层负责建立连接、验证用户身份、进行权限检查等操作。 1. 连接管理 处理客户端的连接请求&#xff0c;包括建立连接、断开连接等操作。维护连接池&#xff0c;提高连接…

35. Three.js案例-创建带阴影的球体与平面

35. Three.js案例-创建带阴影的球体与平面 实现效果 知识点 WebGLRenderer WebGLRenderer 是Three.js中用于渲染场景的主要类之一&#xff0c;它负责将场景中的对象渲染到画布上。 构造器 new THREE.WebGLRenderer(parameters : Object) 参数类型描述parametersObject可选…