当前位置: 首页 > article >正文

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

文章目录

  • 一、`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 不为 null

object 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 转换为 Animal
        animal.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.kler.cn/a/446459.html

相关文章:

  • 【Leecode】Leecode刷题之路第87天之扰乱字符串
  • 04、Vue与Ajax
  • MySQL 在window免安装启动
  • 【Jenkins】pipeline 的基础语法以及快速构建一个 jenkinsfile
  • 深入理解延迟队列:原理、实现与应用
  • 查看Mysql数据库引擎以及修改引擎为innoDB
  • 用bootstrap搭建侧边栏
  • uniapp新建项目hello,什么都没干提示应用未关联服务空间,请在uniCloud目录右键关联服务空间
  • Linux中部署项目
  • 精准采集整车信号:风丘混合动力汽车工况测试
  • Solon 集成 activemq-client
  • Next.js v15- Metadata
  • vimdc
  • 【活动邀请·深圳】深圳COC社区 深圳 AWS UG 2024 re:Invent re:Cap
  • 【c++笔试强训】(第四十一篇)
  • 4_使用 HTML5 Canvas API (3) --[HTML5 API 学习之旅]
  • 青少年编程与数学 02-004 Go语言Web编程 13课题、模板引擎
  • Linux之磁盘管理相关命令
  • nginx长连接配置
  • 二维码:理解二维码 / 生成二维码 / 小程序支持哪种类型的二维码 / 小程序识别GS1码
  • 【postgresql初级使用】小小索引大用途,奇妙的索引让大数据查询提升成百上千倍,多种索引类型的区别,你用对索引了吗?
  • centOS定时任务-cron服务
  • javaFX.(蜜雪冰城点餐小程序)MySQL数据库
  • flask-admin的modelview 实现list列表视图中扩展修改状态按钮
  • 【Prompt Engineering】6 文本扩展
  • ML 系列:第 40 节 — 最大似然MLE 的简单问题