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

news2024/12/23 1:26:28

文章目录

  • 一、`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.coloradmin.cn/o/2263980.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android GO 版本锁屏声音无效问题

问题描述 Android go版本 在设置中打开锁屏音开关&#xff0c;息屏灭屏还是无声音 排查 vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\keyguard\KeyguardViewMediator.java private void setupLocked() {...String soundPath Settings.G…

跟着问题学18——transformer模型详解及代码实战(3)Encode编码器

跟着问题学18——transformer模型详解及代码实战&#xff08;1&#xff09; 跟着问题学18——transformer详解(2)多头自注意力机制-CSDN博客 2.3 残差连接 通过自注意力层我们挖掘提取了原始数据的特征&#xff0c;但编码层中会有多个编码器&#xff0c;这会导致网络层数的加…

React系列(八)——React进阶知识点拓展

前言 在之前的学习中&#xff0c;我们已经知道了React组件的定义和使用&#xff0c;路由配置&#xff0c;组件通信等其他方法的React知识点&#xff0c;那么本篇文章将针对React的一些进阶知识点以及React16.8之后的一些新特性进行讲解。希望对各位有所帮助。 一、setState &am…

【原生js案例】移动端如何实现页面的入场和出场动画

好的css动画&#xff0c;能给用户体验带来很大的提升&#xff0c;同时也能增加app的趣味性&#xff0c;给人眼前一亮的感觉。那如何实现这种全屏的弹窗入场和退场的动画 实现效果 代码实现 UI样式美化 #musicDetails{width: 100%;height: 100%;top:0;left:0;position: absol…

Pyqt6在lineEdit中输入文件名称并创建或删除JSON文件

1、创建JSON文件 代码 import osdef addModulekeyWordFile(self):if "" ! self.lineEdit_module.text():moduleFile self.lineEdit_module.text() .jsonelse:self.toolLogPrinting(请输入模块名称)returnfilePath modulekeyWordFileDir moduleFileif os.path.e…

鸿蒙UI开发——组件滤镜效果

1、概 述 ArkUI为组件提供了滤镜效果设置&#xff0c;背景滤镜、前景滤镜、合成滤镜。我们可以通过以下方式为组件设置对应的滤镜效果。 Text(前景滤镜)// ..其他属性.foregroundFilter(filterTest1) // 通过 foregroundFilter 设置模糊效果Text(背景滤镜)// ...其他属性.bac…

均方误差损失函数(MSE)和交叉熵损失函数详解

为什么需要损失函数 前面的文章我们已经从模型角度介绍了损失函数&#xff0c;对于神经网络的训练&#xff0c;首先根据特征输入和初始的参数&#xff0c;前向传播计算出预测结果&#xff0c;然后与真实结果进行比较&#xff0c;得到它们之间的差值。 损失函数又可称为代价函…

抓包 127.0.0.1 (loopback) 使用 tcpdump+wireshark

直接使用 wireshark无法抓取 127.0.0.1环回的数据包&#xff0c;一种解决方法是先传到路由器再返回&#xff0c;但这样可能造成拥塞。 Linux 先使用tcpdump抓包并输出为二进制文件&#xff0c;然后wireshark打开。 比如 sudo tcpdump -i lo src host localhost and dst host…

免费GIS工具箱:轻松将glb文件转换成3DTiles文件

在GIS地理信息系统领域&#xff0c;GLB文件作为GLTF文件的二进制版本&#xff0c;主要用于3D模型数据的存储和展示。然而&#xff0c;GLB文件的使用频率相对较低&#xff0c;这是因为GIS系统主要处理的是地理空间数据&#xff0c;如地图、地形、地貌、植被、水系等&#xff0c;…

安防监控Liveweb视频汇聚融合平台助力执法记录仪高效使用

Liveweb平台可接入的设备除了常见的智能分析网关与摄像头以外 &#xff0c;还可通过GB28181协议接入执法记录仪&#xff0c;实现对执法过程的全程监控与录像&#xff0c;并对执法轨迹与路径进行调阅回看。那么&#xff0c;如何做到执法记录仪高效使用呢&#xff1f; 由于执法记…

【Unity3D】实现可视化链式结构数据(节点数据)

关键词&#xff1a;UnityEditor、可视化节点编辑、Unity编辑器自定义窗口工具 使用Newtonsoft.Json、UnityEditor相关接口实现 主要代码&#xff1a; Handles.DrawBezier(起点&#xff0c;终点&#xff0c;起点切线向量&#xff0c;终点切线向量&#xff0c;颜色&#xff0c;n…

网络安全核心目标CIA

网络安全的核心目标是为关键资产提供机密性(Confidentiality)、可用性(Availablity)、完整性(Integrity)。作为安全基础架构中的主要的安全目标和宗旨&#xff0c;机密性、可用性、完整性频频出现&#xff0c;被简称为CIA&#xff0c;也被成为你AIC&#xff0c;只是顺序不同而已…

[项目代码] YOLOv8 遥感航拍飞机和船舶识别 [目标检测]

项目代码下载链接 &#xff1c;项目代码&#xff1e;YOLO 遥感航拍飞机和船舶识别&#xff1c;目标检测&#xff1e;https://download.csdn.net/download/qq_53332949/90163939YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为…

去雾Cycle-GAN损失函数

文章目录 GAN-LossIdentity-LossDP-lossCycle-Loss G和F都是生成器 G是hazy → \to → gt F是gt → \to → hazy D y D_y Dy​判别无雾图是真实还是生成的&#xff1f; D x D_x Dx​判别有雾图是真实还是生成的&#xff1f; GAN-Loss 在 DAM-CCGAN 中存在两个判别器 D x D_x D…

2024年企业中生成式 AI 的现状报告

从试点到生产&#xff0c;企业 AI 格局正在被实时改写。我们对 600 名美国企业 IT 决策者进行了调查&#xff0c;以揭示新兴的赢家和输家。 从试点到生产 2024 年标志着生成性人工智能成为企业关键任务的一年。这些数字讲述了一个戏剧性的故事&#xff1a;今年人工智能支出飙升…

组件十大传值

一、defineProps 和 defineEmits defineProps 用于定义子组件接收的 props&#xff0c;即父组件传递给子组件的数据。 接收父组件传递的数据&#xff1a;定义子组件可以接受的属性及其类型。类型检查&#xff1a;确保传递的数据符合预期的类型。 defineEmits 用于定义子组件…

WPF 依赖属性和附加属性

除了普通的 CLR 属性&#xff0c; WPF 还有一套自己的属性系统。这个系统中的属性称为依赖属性。 1. 依赖属性 为啥叫依赖属性&#xff1f;不叫阿猫阿狗属性&#xff1f; 通常我们定义一个普通 CLR 属性&#xff0c;其实就是获取和设置一个私有字段的值。假设声明了 100 个 …

递归实现指数型枚举(递归)

92. 递归实现指数型枚举 - AcWing题库 每个数有选和不选两种情况 我们把每个数看成每层&#xff0c;可以画出一个递归搜索树 叶子节点就是我们的答案 很容易写出每dfs函数 dfs传入一个u表示层数 当层数大于我们n时&#xff0c;去判断每个数字的选择情况&#xff0c;输出被选…

mac 安装graalvm

Download GraalVM 上面链接选择jdk的版本 以及系统的环境下载graalvm的tar包 解压tar包 tar -xzf graalvm-jdk-<version>_macos-<architecture>.tar.gz 移入java的文件夹目录 sudo mv graalvm-jdk-<version> /Library/Java/JavaVirtualMachines 设置环境变…

【WPS安装】WPS编译错误总结:WPS编译失败+仅编译成功ungrib等

WPS编译错误总结&#xff1a;WPS编译失败仅编译成功ungrib等 WPS编译过程问题1&#xff1a;WPS编译失败错误1&#xff1a;gfortran: error: unrecognized command-line option ‘-convert’; did you mean ‘-fconvert’?解决方案 问题2&#xff1a;WPS编译三个exe文件只出现u…