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

文章目录

    • 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.hqwc.cn/news/257213.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

概率测度理论方法(第 2 部分)

一、说明 欢迎回到这个三部曲的第二部分!在第一部分中,我们为测度论概率奠定了基础。我们探索了测量和可测量空间的概念,并使用这些概念定义了概率空间。在本文中,我们使用测度论来理解随机变量。 作为一个小回顾,在第…

贪吃的猴子 - 华为OD统一考试(C卷)

OD统一考试(C卷) 分值: 200分 题解: Java / Python / C 题目描述 一只贪吃的猴子,来到一个果园,发现许多串香蕉排成一行,每串香蕉上有若干根香蕉。每串香蕉的根数由数组numbers给出。猴子获取香…

flask web开发学习之初识flask(三)

文章目录 一、flask扩展二、项目配置1. 直接配置2. 使用配置文件3. 使用环境变量4. 实例文件夹 三、flask命令四、模版和静态文件五、flask和mvc架构 一、flask扩展 flask扩展是指那些为Flask框架提供额外功能和特性的库。这些扩展通常遵循Flask的设计原则,易于集成…

编程实战:自己编写HTTP服务器(系列2:请求)

系列入口:编程实战:自己编写HTTP服务器(系列1:概述和应答)-CSDN博客 本文介绍如何处理请求。 目录 一、概述 二、成员变量 三、接收并分解请求 四、完整代码 五、HTTP处理框架 一、概述 请求和应答结构其实差不多…

电子学会C/C++编程等级考试2021年03月(五级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:最小新整数 给定一个十进制正整数n(0 < n < 1000000000),每个数位上数字均不为0。n的位数为m。 现在从m位中删除k位(0<k < m),求生成的新整数最小为多少? 例如: n = 9128456, k = 2, 则生成的新整数最小为12456…

导入JDBC元数据到Apache Atlas

前言 前期实现了导入MySQL元数据到Apache Atlas, 由于是初步版本&#xff0c;且功能参照Atlas Hive Hook&#xff0c;实现的不够完美 本期对功能进行改进&#xff0c;实现了导入多种关系型数据库元数据到Apache Atlas 数据库schema与catalog 按照SQL标准的解释&#xff0c;…

DDD架构思想专栏一《初识领域驱动设计DDD落地》

引言 最近准备给自己之前写的项目做重构&#xff0c;这是一个单体架构的小项目&#xff0c;后端采用的是最常见的三层架构。因为项目比较简单&#xff0c;其实采用三层架构就完全够了。但是呢&#xff0c;小编最近在做DDD架构的项目&#xff0c;于是就先拿之前写的一个老项目试…

使用React 18、Echarts和MUI实现温度计

关键词 React 18 Echarts和MUI 前言 在本文中&#xff0c;我们将结合使用React 18、Echarts和MUI&#xff08;Material-UI&#xff09;库&#xff0c;展示如何实现一个交互性的温度计。我们将使用Echarts绘制温度计的外观&#xff0c;并使用MUI创建一个漂亮的用户界面。 本文…

pytorch优化之SAM优化器

1. SAM介绍 人机验证 2. 案例 ❀精度优化❀优化策略1&#xff1a;网络SAM优化器_夏天&#xff5c;여름이다的博客-CSDN博客文章浏览阅读3.3k次&#xff0c;点赞10次&#xff0c;收藏30次。精度优化策略&#xff1a;SAM:Sharpness AwarenessMinimization锐度感知最小化论文&…

css 十字分割线(含四等分布局)

核心技术 伪类选择器含义li:nth-child(2)第2个 lili:nth-child(n)所有的lili:nth-child(2n)所有的第偶数个 lili:nth-child(2n1)所有的第奇数个 lili:nth-child(-n5)前5个 lili:nth-last-child(-n5)最后5个 lili:nth-child(7n)选中7的倍数 border-right: 3px solid white;borde…

Java 简易版 TCP UDP聊天

客户端 import java.io.*; import java.net.Socket; import java.util.Date; import javax.swing.*;public class MyClient {private JFrame jf;private JButton jBsend;private JTextArea jTAcontent;private JTextField jText;private JLabel JLcontent;private Date data;pr…

vue3日常知识点学习归纳

1&#xff0c;父子组件传递&#xff1a; 父组件传递参数 <template><div><!-- 子组件 参数&#xff1a;num 、nums --><child :num"nums.num" :doubleNum"nums.doubleNum" increase"handleIncrease"></child>&l…