C# 图解教程 第5版 —— 第17章 转换

news2024/11/25 20:22:00

文章目录

    • 17.1 什么是转换
    • 17.2 隐式转换
    • 17.3 显示转换和强制转换
    • 17.4 转换的类型
    • 17.5 数字的转换
      • 17.5.1 隐式数字转换
      • 17.5.2 溢出检测上下文
      • 17.5.3 显示数字转换
    • 17.6 引用转换
      • 17.6.1 隐式引用转换
      • 17.6.2 显式引用转换
      • 17.6.3 有效显式引用转换
    • 17.7 装箱转换
      • 17.7.1 装箱是创建副本
      • 17.7.2 装箱转换
    • 17.8 拆箱转换
    • 17.9 用户自定义转换
      • 17.9.1 用户自定义转换的约束
      • 17.9.2 用户自定义转换的示例
      • 17.9.3 评估用户自定义转换
      • 17.9.4 多步用户自定义转换的示例
    • 17.10 is 运算符
    • 17.11 as 运算符

17.1 什么是转换

  • 转换是接受一个类型的值并将它用作另一个类型的等价值的过程。
  • 转换后的值应和原值一样,但其类型为目标类型。

17.2 隐式转换

  1. 隐式转换不会丢失数据或精度,C# 会自动做这些转换。

  2. 从位数更少的源类型转换为位数更多的目标类型时,目标中多出来的位需要用 0 或 1 填充。

    • 对于无符号类型,目标类型多出来的最高位都用 0 来进行填充,称为零扩展
    image-20231206215536631
    图17.1 无符号转换中的零扩展
    • 对于有符号类型,额外的最高位用源表达式的符号位进行填充,称为符号扩展
image-20231206215407890
图17.2 有符号转换中的符号扩展
  1. C# 没有无符号扩展。

17.3 显示转换和强制转换

​ C# 不会提供会造成值丢失的自动转换。此时,需要使用强制转换表达式,这称为显示转换

  • 一对圆括号,里面是目标类型。
  • 圆括号后面是源表达式。
image-20231206215923366

​ 使用强制转换表达式,需要承担可能引起的丢失数据的后果。

image-20231206220011328
图17.3 强制转换 ushort 为 byte

17.4 转换的类型

  • 除了标准转换,还可以为自定义类型定义隐式转换和显示转换。
  • 有一个预定义的转换类型,称为装箱,可以将任何值类型转换为:
    • object 类型。
    • System.ValueType 类型。
  • 拆箱可以将一个装箱的值转换为原始类型。
image-20231206220245548
图17.4 转换的类型

17.5 数字的转换

​ 数字类型可以相互转换,但有些转换必须是显式的。

image-20231207000033891
图17.5 数字转换

17.5.1 隐式数字转换

  • 箭头方向表示存在从源类型到目标类型的隐式转换。
  • 若没有沿着箭头方向的路径,则该类型转换必须是显式的。
image-20231207000346245
图17.6 隐式数字转换

17.5.2 溢出检测上下文

​ 使用 checked 运算符或 checked 语句检测类型转换是否溢出。

  • 代码片段是否被检查称作溢出检测上下文
    • 如果指定一个表达式或一个代码为 checked,CLR 会在转换产生溢出时抛出 OverflowException 异常。
    • 如果代码不是 checked,转换会继续,不论是否产生溢出。
  • 默认的溢出检测上下文是不检查。

(1)checked 和 unchecked 运算符

image-20231207000723523
  • 在 unchecked 上下文中,会忽略溢出,结果值为 208。
  • 在 checked 上下文中,抛出了 OverflowException 异常。
image-20231207000756617 image-20231207000856758

(2)checked 语句和 unchecked 语句

​ checked 和 unchecked 控制的是一块代码中的所有转换,而不是单个表达式。

image-20231207001003795

17.5.3 显示数字转换

image-20231207001029226
图17.7 显式数字转换

(1)整数类型到整数类型

​ 如果转换会丢失数据:

  • checked 时,则抛出 OverflowException 异常。
  • unckecked 时,丢失的位不会发出警告。
image-20231207001157207
图17.8 整数到整数的显示转换

(2)float 或 double 转到整数类型

​ 如果转换会丢失数据:舍掉小数,截断为最接近的整数。

  • checked 时,则抛出 OverflowException 异常。
  • unckecked 时,C# 将不定义其值是什么。
image-20231207001531466
图17.9 转换 float 或 double 为整数类型

(3)decimal 到整数类型

​ 如果结果值不在目标类型的范围内,则 CLR 会抛出 OverflowException 异常。

image-20231207001117587
图17.10 转换 decimal 到整数

(4)double 到 float

​ double 被舍入到最接近的 float 值:

  • 值太小,则被设为 +0 或 -0。
  • 值太大,则被设为 +∞ 或 -∞。
image-20231207001853450
图17.11 转换 double 到 float

(5)float 或 double 到 decimal

  • 值太小,则被设为 0。
  • 值太大,则抛出 OverflowException 异常。
image-20231207001955651
图17.12 转换 float 或 double 到 decimal

(6)decimal 到 float 或 double

​ 总是会成功,但可能会损失精度。

image-20231207002055355
图17.13 转换 decimal 到 float 或 double

17.6 引用转换

​ 引用类型对象由内存中的两部分组成:引用和数据。

​ 引用转换接受源引用并返回指向堆中同一位置的引用,但是将引用“标记”为其他类型。

  • 对于 myVar1,引用对象看上去是类型 B 的对象(实际上就是)。
  • 对于 myVar2,同样的对象看上去像类型 A。
image-20231207130723138 image-20231207130742716
图17.14 引用转换返回与对象关联的不同类型

17.6.1 隐式引用转换

  • 所有引用类型可以被隐式转换为 object 类型。
  • 任何接口可以隐式转换为其继承的接口。
  • 类可以隐式转换为:
    • 继承链中的任何类。
    • 实现的任何接口。
image-20231207130958291
图17.15 类和接口的隐式转换
  • 委托可以隐式转换为 .NET BCL 类和接口。
  • ArrayS 数组(元素类型为 Ts)可以隐式转换为:
    • .NET BCL 类和接口。
    • 另一个满足如下条件的数组 ArrayT(元素类型为 Tt):
      1. 数组维度和 ArrayS 相同。
      2. Ts 和 Tt 都是引用类型。
      3. Ts 能隐式转换为 Tt。
image-20231207131257551
图17.16 委托和数组的隐式转换

17.6.2 显式引用转换

​ 显式引用转换是从普通类型到更精确类型的引用转换,包括:

  1. 从 object 到任何引用类型的转换。
  2. 从基类到派生类的转换。

​ 例如,将基类 A 的引用转换到派生类 B,并赋值给变量 myVar2.

  • 如果 myVar2 尝试访问 Field2,将会导致内存错误。
  • 这种不正确的强制转换会在运行时抛出 InvalidCastException 异常,但不会导致编译错误。
image-20231207131740441
图17.17 无效的转换抛出运行时异常

17.6.3 有效显式引用转换

​ 以下 3 种显示转换能够成功进行:

  1. 显示转换没有必要。

    即,已经发生了隐式转换。

image-20231207131957636
  1. 源引用为 null。

    尽管这样的类型转换通常不安全,但 C# 还是允许的。

image-20231207132043049
  1. 源引用指向的实际数据可以安全地进行隐式转换。
    • myVar2 看上去指向类型 A 的数据,但实际上指向的是类型 B。
image-20231207132224429
图17.18 强制转换到安全类型

17.7 装箱转换

​ 装箱是一种隐式转换,接受值类型,在堆上创建一个完整的引用类型对象并返回其引用。

​ 常见的装箱场景是将值类型当做参数传递给方法,但参数类型时对象的数据类型,装箱过程具体如下:

  • 在堆上创建 int 类型对象。
  • 将 i 的值复制给 int 对象。
  • 返回 int 对象的引用 oi。
image-20231207132702276
图17.19 装箱从值类型穿件了完整的引用类型

17.7.1 装箱是创建副本

​ 装箱返回的是值的引用类型副本。即,装箱之后,值有两份副本——原始值类型和引用类型副本,每一个都可以独立操作。

image-20231207132927683 image-20231207133001587 image-20231207133021488
图17.20 装箱创建了一份可以被独立操作的副本

17.7.2 装箱转换

​ 任何值类型 ValueTypeS 都可以被隐式转换为 object、System.ValueType 或 InferfaceT 类型(如果 ValueTypeS 实现了 InferfaceT)。

image-20231207133212039
图17.21 装箱是值类型到引用类型的隐式转换

17.8 拆箱转换

  • 拆箱是显式转换。
  • 系统在把值拆箱为 ValueTypeT 时执行了如下步骤:
    1. 检测到要拆箱的对象实际是 ValueTypeT 的装箱值。
    2. 将对象的值复制到变量。
  • 尝试将一个值拆箱为非原始类型时会抛出 InvalidCastException 异常。
image-20231207133524136 image-20231207133604848 image-20231207133618889 image-20231207133635312
图17.22 拆箱转换

17.9 用户自定义转换

​ 可以为类和结构定义隐式和显式转换。

  • 需要 public 和 static 修饰符。
  • implicit 和 explicit 分别表示隐式和显式转换。
image-20231207133847913

17.9.1 用户自定义转换的约束

  • 只可以为类和结构定义。
  • 不能重定义标准隐式或显式转换。
  • 对于源类型 S 和目标类型 T:
    • S 和 T 类型不能相同。
    • S 和 T 不能有继承关系。
    • S 和 T 不能同时为接口或 object。
    • 转换运算符必须定义在 S 或 T 类型的内部。
    • 不能同时声明隐式转换和显式转换。

17.9.2 用户自定义转换的示例

​ 隐式转换示例:

image-20231207134152236 image-20231207134244737 image-20231207134259771

​ 若使用显式转换,则需要:

image-20231207134344549

17.9.3 评估用户自定义转换

image-20231207134420162
图17.23 单步用户自定义转换

​ 完整转换中最多可以有 3 个步骤:

  1. 预备标准转换。
  2. 用户自定义转换。
  3. 后续标准转换。

​ 用户自定义转换只能有一次。

image-20231207134539358
图17.24 多步用户自定义转换

17.9.4 多步用户自定义转换的示例

image-20231207134652719 image-20231207134730222 image-20231207134746499
图17.25 从 Employee 转换到 float

17.10 is 运算符

​ is 运算符用于检查转换是否能成功。

image-20231207134912633

​ 以下 3 种转换适用于 is 运算符:

  1. 引用转换。
  2. 装箱转换。
  3. 拆箱转换。

​ is 运算符不能用于用户自定义转换。

17.11 as 运算符

​ as 运算符和强制转换运算符类似,但不会抛出异常,转换失败仅返回 null。

image-20231207135137893

​ as 运算符只能用于引用转换和装箱转换。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1301310.html

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

相关文章

Python 全栈体系【四阶】(三)

第三章 matplotlib 一、基本绘图 1. 绘图核心 API 案例: 绘制简单直线 import numpy as np import matplotlib.pyplot as plt# 绘制简单直线 x np.array([1, 2, 3, 4, 5]) y np.array([3, 6, 9, 12, 15])plt.plot(x, y) plt.show() # 显示图片,阻塞…

《Mamba: Linear-Time Sequence Modeling with Selective State Spaces》阅读笔记

论文标题 《Mamba: Linear-Time Sequence Modeling with Selective State Spaces》 作者 Albert Gu 和 Tri Dao 初读 摘要 Transformer 架构及其核心注意力模块 地位:目前深度学习领域普遍的基础模型。 为了解决 Transformers 在长序列上的计算效率低下的问题…

【视频笔记】古人智慧与修行

古人的智慧 相由心生、老子悟道、佛祖成佛 多一些思考,多一些精神修炼。 除非我们今天能够产生与人类科技发展相并行的精神变革,否则永远可能也无法跳脱出历史的轮回。 视频来源 曾仕强教授周易的智慧 太极两仪四象八卦 一生二,二生三&…

gRPC基本用法:以人脸识别为例,搭建一个简单的gRPC服务

标题 0. gRPC简介 相关网站: 中文文档:gRPC 官方文档中文版_V1.0 官网:gRPC 介绍(以下引自官方文档中文版中的介绍): gRPC是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提…

LANDSAT_7/02/T1/RAW的Landsat7_C2_RAW类数据集

Landsat7_C2_RAW是指Landsat 7卫星的数据集,采用的是Collection 2级别的数据处理方法,对应的是Tier 1级别的原始数据(RAW)。该数据集包括了Landsat 7卫星从1999年4月15日开始的所有数据,共涵盖了全球范围内的陆地和海洋…

性格内向怎么办?如何改变性格内向?

性格内向和外向并没有优劣之分,性格内向也不是坏事,但从人际交往和事务处理的角度来看,内向性格确实不如外向的有优势,所以这也是很多人希望改变自己内向性格的原因。 此外性格内向也容易称为心理问题的替代词,比如&a…

Data Mining数据挖掘—2. Classification分类

3. Classification Given a collection of records (training set) – each record contains a set of attributes – one of the attributes is the class (label) that should be predicted Find a model for class attribute as a function of the values of other attribu…

【Linux】进程间通信之共享内存/消息队列/信号量

文章目录 一、共享内存的概念及原理二、共享内存相关接口说明1.shmget函数2.ftok函数3.shmat函数4.shmdt函数5.shmctl函数 三、用共享内存实现server&client通信1.shm_server.cc2.shm_client.cc3.comm.hpp4.查看ipc资源及其特征5.共享内存的优缺点6.共享内存的数据结构 四、…

ADAudit Plus:强大的网络安全卫士

随着数字化时代的不断发展,企业面临着越来越复杂和多样化的网络安全威胁。在这个信息爆炸的时代,保护组织的敏感信息和确保网络安全已经成为企业发展不可或缺的一环。为了更好地管理和监控网络安全,ADAudit Plus应运而生,成为网络…

【队列】数据也得排队

目录 引言 队列的概念 队列的实现 单向链表队列 结构 初始化 入队 出队 取队头 取队尾 求个数 判空 内存释放 总结 引言 队列,这个看似普通的数据结构,其实隐藏着无尽的趣味和巧思。就像单向链表这把神奇的魔法钥匙,它能打开队…

解决Git提交错误分支

如果 Git 提交到错误的分支&#xff0c;可以通过以下步骤将其转移到正确的分支上&#xff1a; 1.检查当前所在的分支&#xff0c;可以通过 git branch 命令查看。 git branch2.切换到正确的分支&#xff0c;可以通过 git checkout <正确的分支名> 命令进行切换。 git …

vue3-vite前端快速入门教程 vue-element-admin

Vue3快速入门学习 初始化项目 # 创建项目 npm create vitelatest my-vue-app -- --template vue # 安装依赖 npm i # 运行 npm run dev 模板语法 文本插值​ 最基本的数据绑定形式是文本插值&#xff0c;它使用的是“Mustache”语法 (即双大括号)&#xff1a; <span&g…

三相不平衡电压的正负序分析

1、什么是正负序&#xff1f; ABC 正序 ACB 负序 2、在abc坐标系下 接着利用矢量的旋转消去其它分量。。。 同理&#xff0c;得到其它的所有正负序的分量abc 3、在α/β坐标系下&#xff0c; 依次算出正负序的α/β来表示的abc 有一点需要特别注意&#xff0c;可以看到…

贪心其实很简单

关卡名 认识贪心思想 我会了✔️ 内容 1.复习一维数组&#xff0c;对数组进行多轮插入或者删除时会频繁移动数据&#xff0c;理解双指针是如何避免该问题的 ✔️ 2.理解滑动窗口的原理和适用场景 ✔️ 3.掌握窗口变与不变的两种情况是如何用来解题的 ✔️ 1.难以解释的贪心…

基于SpringBoot+Vue前后端分离的商城管理系统(Java毕业设计)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

【Linux】进程周边001之进程概念

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.基本概念 2.描述进程-PCB…

贪心算法及相关题目

贪心算法概念 贪心算法是指&#xff0c;在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。也就是说&#xff0c;不从整体最优上加以考虑&#xff0c;算法得到的是在某种意义上的局部最优解 。 贪心算法性质&#xff08;判断是否可以使用贪心算法&#xff09; 1、贪…

【SpringBoot教程】SpringBoot 创建定时任务(配合数据库动态执行)

作者简介&#xff1a;大家好&#xff0c;我是撸代码的羊驼&#xff0c;前阿里巴巴架构师&#xff0c;现某互联网公司CTO 联系v&#xff1a;sulny_ann&#xff08;17362204968&#xff09;&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗…

DDD系列 - 第6讲 仓库Repository及Mybatis、JPA的取舍(一)

目录 一、领域层定义仓库接口1.1 设计聚合1.2 定义仓库Repository接口二 、基础设施层实现仓库接口2.1 设计数据库2.2 集成Mybatis2.3 引入Convetor2.4 实现仓库三、回顾一、领域层定义仓库接口 书接上回,之前通过一个关于拆解、微服务、面向对象的故事,向大家介绍了如何从微…

mysql中的DQL查询

表格为&#xff1a; DQL 基础查询 语法&#xff1a;select 查询列表 from 表名&#xff1a;&#xff08;查询的结果是一个虚拟表格&#xff09; -- 查询指定的列 SELECT NAME,birthday,phone FROM student -- 查询所有的列 * 所有的列&#xff0c; 查询结果是虚拟的表格&am…