16 转换

目录

16.1 什么是转换

16.2 隐式转换

16.3 显示转换和强制转换

强制转换

16.4 转换的类型 

16.5 数字的转换

 16.5.1 隐式数字转换

16.5.2 溢出检测上下文

1、checked和unchecked运算符;

2、checked语句和unchecked语句

 16.5.3 显示数字转换

1.整数类型到整数类型 

 2.float或double转到整数类型

3.decimal到整形类型

4.double到float

5.float或double到decimal

6.decmal 到float或double

 16.6 引用转换

16.6.1 隐式引用转换

16.6.2 显示引用转换

 16.6.3 有效显示引用转换

16.7 装箱转换

16.7.1 装箱是创建副本 

 16.7.2 装箱转换

16.8 拆箱转换

拆箱转换 

16.9 用户自定义转换

 16.9.1 用户自定义转换的约束

16.10 is运算符

16.11 as运算符


16.1 什么是转换

声明两个不同类型的变量,然后把一个变量(源)的值赋值给另一个变量(目标)的过程就发生了类型转换。16 转换_第1张图片

  • 转换(conversion)是接受一个类型的值并使用它作为另一个类型的等价值过程。
  • 转换后的值应和原值一样,但其类型为目标类型 
  • var1是short类型的16位有符号整数,初始值是5,var2是sbyte类型的8位有符号整数,初始值为10.
  • 把var1的值赋值给var2.由于他们是两种不同的类型,在进行赋值之前,var1的值必须转换为var2类型相同的值类型。这将通过强制类型转换表达式来实现,稍后我们就会看到。
  • var1的值和var2的值都没有改变。尽管称之为转换,但是只代表原值作为目标类型来使用,不是将源值转换为目标类型

16 转换_第2张图片

16.2 隐式转换

 有些类型的转换不会丢失数据或精度,例如将8位的值转换为16位是非常容易的,而且不回丢失数据

  • 语言自动做的转换,叫做隐式转换。
  • 从位数更少的源转换为位数更多的目标类型,目标中多出来的位需要用0或1填充。
  • 当从更小的无符号类型转换为更大的无符号类型时,目标类型多出来的最高位都以0进行填充,这叫做0扩展;

16 转换_第3张图片

  • 对于有符号类型的转换而言,额外的高位用源表达式的符号为进行填充。
  • 这样就维持了被转换的值得正确符号和大小。
  • 这叫做符号扩展

 16 转换_第4张图片

16.3 显示转换和强制转换

如果把短类型转换为长类型,对于长类型来说,保存所有短类型的字符很简单。然而在其他情况下,目标类型也许无法在不损失数据的情况下提供源值。

  • ushort可以保存0·65535之间的值;
  • byte只能保存0·255之间的值
  • 只要希望转换的ushort的值小于256,那么就不会损失数据。然而,如果更大,最高位的数据会丢失。 

16 转换_第5张图片

强制转换

对于预定义的类型,C#会自动将一个数据类型转换为另一个数据类型,但只是针对那些从源类型到目标类型不会发生数据丢失的情况。也就是说,对于源类型的任意值再被转换为目标类型时会丢失的情况,语言是不会提供这两种类型的自动转换的。如果希望对这样的类型转换就必须使用显式转换,强制类型转换表达式; 

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

我们使用强制转换表达式的时候,就意味着要承担执行操作可能会引起丢失数据的情况,16 转换_第6张图片 

16.4 转换的类型 

有很多标准的。预定义的用于数字和引用类型的转换

16 转换_第7张图片

  •  除了标准转换,还可以为自定义类型定义隐式转换(implicit)和显示转换(explicit)
  • 还有一个预定义的转换类型,叫做装箱,可以将任何值类型转换为object类型,或者System.ValueType
  • 拆箱可以将一个装箱的值转换为原始类型;

16.5 数字的转换

任何数字类型都可以转换为其他数字类型,一些转换是隐式的,而另外一些转换则必须是显式地

16 转换_第8张图片

 16.5.1 隐式数字转换

  • 如果有路径,从源类型到目标类型可以按照箭头进行隐式转换。
  • 任何在从源类型到目标类型的箭头方向上没有路径的数字转换都必须是显示转换。

16 转换_第9张图片

16.5.2 溢出检测上下文

显示转换可能会失去数据并且不能在目标类型同等的表示源值。对于整数类型,C#给我们提供了选择运行时是否应该进行类型转换时检测结果溢出的能力。这将通过checked运算符和checked语句来实现。

  • 代码片段能否检测上下文。
  1. 如果我们制定一个表达式或一段代码为checked,CLR会在转换产生溢出时抛出一个OverflowException异常。
  2. 如果代码不是checked,转换会继续而不管是否会产生溢出。
  • 默认的溢出检测上下文是不检查。

1、checked和unchecked运算符;

checked和unchecked运算符控制表达式的溢出检测上下文。表达式放置在一对圆括号内并且不能是一个方法。语法如下所示:

  • checked(表达式)
  • unchecked(表达式)

 16 转换_第10张图片

2、checked语句和unchecked语句

checked和unchecked运算符用于圆括号内的单个表达式。而checked和unchecked语句执行相同的功能,但控制的是一块代码中的所有转换,而不是单个表达式。

checked语句和unchecked语句可以被嵌套在任意层次。

16 转换_第11张图片

 16.5.3 显示数字转换

隐式转换不会丢失数据,但是显示转换会丢失数据:以下介绍各种显示数字转换:

16 转换_第12张图片

1.整数类型到整数类型 

在checked的情况下如果转换会丢失,操作就会抛出OverflowException异常。在unchecked情况下,丢失的位不会发出警告。

16 转换_第13张图片

 2.float或double转到整数类型

当把浮点类型转换为整数类型时,值会舍掉小数截断为最近的整数。

  • 如果溢出检测上下文是checked,则CLR会抛出OverflowException;
  • 如果上下文是unchecked,则C#将不定义它的值应该是什么。

3.decimal到整形类型

当从decimal转换到整数类型时,如果结果值不在目标类型额范围内,则CLR会抛出OverflowException

4.double到float

float类型的值占32位,而double类型的值占64位,double类型的值被舍入最接近的float类型的值

  • 如果值太小而不能用float,那么值会被设置为正或负0
  • 如果值太大而不能用float表示,则值会被设置为无穷大(正负)

16 转换_第14张图片16 转换_第15张图片

5.float或double到decimal

  • 如果值太小而不能用decimal类型表示,那么值会被设置为0;
  • 如果值太大,那么CLR会抛出OverflowExcept异常。 

16 转换_第16张图片

6.decmal 到float或double

从decmal类型转换到float类型总会成功。但是会损失精度

16 转换_第17张图片

 16.6 引用转换

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

  • 由引用保存的那部分信息是指向的数据类型。
  • 引用转换接受源引用并返回一个指向堆中同一位置的引用,但是把引用“标记”为其他类型。

16 转换_第18张图片

16.6.1 隐式引用转换

  • 所有引用类型可以被隐式转换为object类型。
  • 任何类型可以隐式转换到它继承的的接口; 
  • 类可以隐式转换到:它继承的任何类,它实现的任何接口

16 转换_第19张图片

 

委托可以隐式转换成图.NET BCL接口。Arrays数组,其中的元素是Ts类型可以隐式转换为

  • .NET BCl类和接口;
  • 另一个数组ArrayT,其中的元素是Tt类型(如果满足下面的所有条件)。
  1. 两个数组有一样的维度。
  2. 元素类型Ts和Tt都是引用类型,不是值类型
  3. 在类型Ts和Tt中存在隐式转换

16 转换_第20张图片

16.6.2 显示引用转换

显示引用转换是从一个普通类型到一个更精确类型的引用转换。

显示转换包括:

  • 从object到任何引用类型的转换;
  • 从基类到从它继承的类的转换。

如果转换的类型不受限制,很可能会导致我们很容易地尝试引用在实际并不存在的类成员。然而,编译器确实允许这样转换。到那时,如果系统在运行时遇到它们则会抛出一个异常,

16 转换_第21张图片

 16.6.3 有效显示引用转换

在运行时能成功进行(也就是不抛出InvalidCastException异常)的显示转换有3种情况。

第一种语言已经为我们进行了隐式转换:

第二种:源引用是null:

 

第三种:由于源引用指向的实际数据可以被安全的进行隐式转换:

 

16.7 装箱转换

包括值类型在内的所有C#类型都派生自object。然儿1,值类型是高级轻量的类型,因为默认情况下在堆上不包括它们的对象组件。如果需要对象组件,我们可以使用装箱。装箱是一种隐式转换,它接受值值类型的值,根据这个值在堆上创建一个完整的引用类型对象并返回对象引用: 

16 转换_第22张图片

16.7.1 装箱是创建副本 

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

16 转换_第23张图片

 16.7.2 装箱转换

任何值类型ValueTypes都可以被隐式转换为object类型。System.Value或InferfaceT(如果ValueTypes实现了InterfaceT)。

16 转换_第24张图片

16.8 拆箱转换

拆箱(unboxing)是把装箱后的对象转换回值类型的过程。

拆箱是显示转换.

系统在把值拆箱成ValueTypeT时执行如下的步骤:

它检测到要拆箱的对象实际是ValueType的装箱值;

它把对象的值复制到变量:

16 转换_第25张图片

尝试将一个值拆箱为非原始类型时就会抛出一个InvalidCastException异常。

拆箱转换 

16 转换_第26张图片

16.9 用户自定义转换

除了标准转转,我们还可以为类和结构自定义 隐式和显示转换。

除了implicit和ecplicit关键字之外,隐式和显式转换的声明语法是一样的。

需要public和static修饰符。

16 转换_第27张图片

 16.9.1 用户自定义转换的约束

  • 只可以为类和结构定义用户自定义转换。
  • 不能重定义标准隐式转换或显示转换。
  • 对于源类型S和目标类型T:
  1. S和T必须是不同类型;
  2. S和T不能通过继承关系维持
  3. S和T不能是接口类型或object类型
  4. 转换运算符必须是S或T的成员。
  • 对于相同的目标类型和源,我们不能声明隐式转换和显示转换。

16.10 is运算符

有些转换是不会成功的,并且会在运行时抛出一个InvalidCastException异常。我们可以使用is运算符来检查转换是否会成功完成,从而避免盲目尝试转换。

is运算符的语法如下,Expr是源表达式:

16 转换_第28张图片

16.11 as运算符

as运算符和强制转换运算符类似,只是它不会抛出异常。如果转换失败,它返回的null而不是抛出异常。

16 转换_第29张图片 

 需要注意的是as 和 is都只能用于引用转换和装箱转换。它们不能用于用户自定义转换或到值类型的转换

 

 

 

你可能感兴趣的:(C#,c#,开发语言)