LIVE

导航

C# Language Specification 1.2 之六 转换

1. 转换

转换 (conversion) 使一种类型的表达式可以被视为另一种类型。转换可以是隐式的 (implicit) 或显式的 (explicit)这将确定是否需要显式地强制转换。例如 int 类型到 long 类型的转换是隐式的因此 int 类型的表达式可隐式地按 long 类型处理。从 long 类型到 int 类型的反向转换是显式的,因此需要显式地强制转换。

int a = 123;
long b = a;        // implicit conversion from int to long
int c = (int) b;   // explicit conversion from long to int

某些转换由语言定义。程序也可以定义自己的转换 6.4

1.1 隐式转换

下列转换属于隐式转换

·         标识转换

·         隐式数值转换

·         隐式枚举转换。

·         隐式引用转换

·         装箱转换

·         隐式常量表达式转换

·         用户定义的隐式转换

隐式转换可以在多种情况下发生包括函数成员调用 7.4.3 、强制转换表达式 7.6.6 和赋值 7.13

预定义的隐式转换总是会成功从来不会导致引发异常。正确设计的用户定义隐式转换同样应表现出这些特性。

1.1.1 标识转换

标识转换是在同一类型可为任何类型内进行转换。这种转换的存在,仅仅是为了使已具有所需类型的实体可被认为是可转换的(转换为该类型)。

1.1.2 隐式数值转换

隐式数值转换为

·         sbyte shortintlongfloatdouble decimal

·         byte shortushortintuintlongulongfloatdouble decimal

·         short intlongfloatdouble decimal

·         ushort intuintlongulongfloatdouble decimal

·         int longfloatdouble decimal

·         uint longulongfloatdouble decimal

·         long floatdouble decimal

·         ulong floatdouble decimal

·         char ushortintuintlongulongfloatdouble decimal

·         float double

intuintlong ulong float 以及从 long ulong double 的转换可能导致精度损失但决不会影响到它的数量级。其他的隐式数值转换决不会丢失任何信息。

不存在向 char 类型的隐式转换因此其他整型的值不会自动转换为 char 类型。

1.1.3 隐式枚举转换

隐式枚举转换允许将 decimal-integer-literal 0 转换为任何 enum-type

1.1.4 隐式引用转换

隐式引用转换为

·         从任何 reference-type object

·         从任何 class-type S 到任何 class-type T前提是 S 是从 T 派生的

·         从任何 class-type S 到任何 interface-type T前提是 S 实现了 T

·         从任何 interface-type S 到任何 interface-type T前提是 S 是从 T 派生的

·         从元素类型为 SE array-type S 到元素类型为 TE array-type T前提是以下所列条件均为真):

o        S T 只是元素类型不同。换言之S T 具有相同的维数。

o        SE TE 都是 reference-type

o        存在从 SE TE 的隐式引用转换。

·         从任何 array-type System.Array

·         从任何 delegate-type System.Delegate

·         null 类型到任何 reference-type

隐式引用转换是指一类 reference-type 之间的转换这种转换总是可以成功因此不需要在运行时进行任何检查。

引用转换无论是隐式的还是显式的都不会更改被转换的对象的引用标识。换言之,虽然引用转换可能更改引用的类型,但决不会更改所引用对象的类型或值。

1.1.5 装箱转换

装箱转换允许任何 value-type 隐式转换为 object System.ValueType 类型或由该 value-type 实现的任何 interface-type。将 value-type 的一个值装箱包括以下操作分配一个对象实例然后将 value-type 的值复制到该实例中。结构可装箱为类型 System.ValueType,因为该类型是所有结构的基类(第 11.3.2 节)。

有关装箱转换的介绍详见第 4.3.1 节。

1.1.6 隐式常量表达式转换

隐式常量表达式转换允许进行以下转换

·         int 类型的 constant-expression 7.15 可以转换为 sbytebyteshortushortuint ulong 类型前提是 constant-expression 的值在目标类型的范围内

·         long 类型的 constant-expression 可以转换为 ulong 类型前提是 constant-expression 的值不为负

1.1.7 用户定义的隐式转换

用户定义的隐式转换由以下三部分组成先是一个标准的隐式转换可选);然后是执行用户定义的隐式转换运算符最后是另一个标准的隐式转换可选。计算用户定义的转换的精确规则详见第 6.4.3 节中的说明。

1.2 显式转换

下列转换属于显式转换

·         所有隐式转换。

·         显式数值转换。

·         显式枚举转换。

·         显式引用转换。

·         显式接口转换。

·         拆箱转换。

·         用户定义的显式转换。

显式转换可在强制转换表达式 7.6.6 中出现。

显式转换集包括所有隐式转换。这意味着允许使用冗余的强制转换表达式。

不是隐式转换的显式转换是这样的一类转换它们不能保证总是成功知道有可能丢失信息变换前后的类型显著不同以至值得使用显式表示法。

1.2.1 显式数值转换

显式数值转换是指从一个 numeric-type 到另一个 numeric-type 的转换此转换不能用已知的隐式数值转换 6.1.2 实现它包括

·         sbyte byteushortuintulong char

·         byte sbyte char

·         short sbytebyteushortuintulong char

·         ushort sbytebyteshort char

·         int sbytebyteshortushortuintulong char

·         uint sbytebyteshortushortint char

·         long sbytebyteshortushortintuintulong char

·         ulong sbytebyteshortushortintuintlong char

·         char sbytebyte short

·         float sbytebyteshortushortintuintlongulongchar decimal

·         double sbytebyteshortushortintuintlongulongcharfloat decimal

·         decimal sbytebyteshortushortintuintlongulongcharfloat double

由于显式转换包括所有隐式和显式数值转换因此总是可以使用强制转换表达式 7.6.6 从任何 numeric-type 转换为任何其他的 numeric-type

显式数值转换有可能丢失信息或导致引发异常。显式数值转换按下面所述处理:

·         对于从一个整型到另一个整型的转换处理取决于该转换发生时的溢出检查上下文 7.5.12 ):

o        checked 上下文中如果源操作数的值在目标类型的范围内转换就会成功但如果源操作数的值在目标类型的范围外则会引发 System.OverflowException

o        unchecked 上下文中转换总是会成功并按下面这样继续。

·         如果源类型大于目标类型则截断源值截去源值中容不下的最高有效位。然后将结果视为目标类型的值。

·         如果源类型小于目标类型则源值或按符号扩展或按零扩展以使它的大小与目标类型相同。如果源类型是有符号的,则使用按符号扩展;如果源类型是无符号的,则使用按零扩展。然后将结果视为目标类型的值。

·         如果源类型的大小与目标类型相同则源值被视为目标类型的值。

·         对于从 decimal 到整型的转换源值向零舍入到最接近的整数值该整数值成为转换的结果。如果转换得到的整数值不在目标类型的范围内则会引发 System.OverflowException

·         对于从 float double 到整型的转换处理取决于发生该转换时的溢出检查上下文
7.5.12
):

o        checked 上下文中,如下所示进行转换:

·         如果操作数的值是 NaN 或无穷大,则引发 System.OverflowException

·         否则,源操作数会向零舍入到最接近的整数值。如果该整数值处于目标类型的范围内,则该值就是转换的结果。

·         否则,引发 System.OverflowException

o        unchecked 上下文中,转换总是会成功并按下面这样继续。

·         如果操作数的值是 NaN infinite则转换的结果是目标类型的一个未经指定的值。

·         否则源操作数会向零舍入到最接近的整数值。如果该整数值处于目标类型的范围内,则该值就是转换的结果。

·         否则转换的结果是目标类型的一个未经指定的值。

·         对于从 double float 的转换double 值舍入到最接近的 float 值。如果 double 值过小无法表示为 float 则结果变成正零或负零。如果 double 值过大,无法表示为 float 值,则结果变成正无穷大或负无穷大。如果 double 值为NaN则结果仍然是 NaN

·         对于从 float double decimal 的转换源值转换为用 decimal 形式来表示并且在需要时将它在第 28 位小数位数上舍入到最接近的数字 4.1.7 。如果源值过小,无法表示为 decimal,则结果变成零。如果源值为 NaN、无穷大或者太大而无法表示为 decimal则将引发 System.OverflowException

·         对于从 decimal float double 的转换decimal 值舍入到最接近的 double float 值。虽然这种转换可能会损失精度但决不会导致引发异常。

1.2.2 显式枚举转换

显式枚举转换为

·         sbytebyteshortushortintuintlongulongcharfloatdouble decimal 到任何 enum-type

·         从任何 enum-type sbytebyteshortushortintuintlongulongcharfloatdouble decimal

·         从任何 enum-type 到任何其他 enum-type

两种类型之间的显式枚举转换是通过将任何参与的 enum-type 都按该 enum-type 的基础类型处理然后在产生的类型之间执行隐式或显式数值转换进行的。例如,给定具有 int 基础类型的 enum-type E,从 Ebyte 的转换按从 intbyte 的显式数值转换(第 6.2.1 节)处理,而从 byteE 的转换按从 byteint 的隐式数值转换(第 6.1.2 节)处理。

1.2.3 显式引用转换

显式引用转换为

·         object 到任何其他 reference-type

·         从任何 class-type S 到任何 class-type T前提是 S T 的基类

·         从任何 class-type S 到任何 interface-type T前提是 S 未密封并且 S 不实现 T

·         从任何 interface-type S 到任何 class-type T前提是 T 未密封或 T 实现 S

·         从任何 interface-type S 到任何 interface-type T前提是 S 不是从 T 派生的

·         从元素类型为 SE array-type S 到元素类型为 TE array-type T前提是以下所列条件均为真):

o        S T 只是元素类型不同。换言之S T 具有相同的维数。

o        SE TE 都是 reference-type

o        存在从 SE TE 的显式引用转换。

·         System.Array 以及它实现的接口到任何 array-type

·         System.Delegate 以及它实现的接口到任何 delegate-type

显式引用转换是那些需要运行时检查以确保它们正确的引用类型之间的转换。

为了使显式引用转换在运行时成功源操作数的值必须为 null或源操作数所引用的对象的实际类型必须是一个可通过隐式引用转换 6.1.4 转换为目标类型的类型。如果显式引用转换失败,则将引发 System.InvalidCastException

引用转换无论是隐式的还是显式的都不会更改被转换的对象的引用标识。换言之,虽然引用转换可能更改引用的类型,但决不会更改所引用对象的类型或值。

1.2.4 拆箱转换

拆箱转换允许从类型 object System.ValueType 到任何 value-type或者从任何 interface-type 到实现了该 interface-type 的任何 value-type 进行显式转换。一个拆箱操作包括以下两个步骤:首先检查对象实例是否为给定 value-type 的一个装了箱的值,然后将该值从实例中复制出来。结构可以从类型 System.ValueType 进行拆箱,因为该类型是所有结构的基类(第 11.3.2 节)。

有关拆箱转换的进一步介绍详见第 4.3.2 节。

1.2.5 用户定义的显式转换

用户定义的显式转换由以下三个部分组成先是一个标准的显式转换可选),然后是执行用户定义的隐式或显式转换运算符最后是另一个标准的显式转换可选。计算用户定义的转换的精确规则详见第 6.4.4 节中的说明。

1.3 标准转换

标准转换是那些预先定义的转换它们可以作为用户定义转换的组成部分出现。

1.3.1 标准隐式转换

下列隐式转换属于标准隐式转换

·         标识转换 6.1.1

·         隐式数值转换 6.1.2

·         隐式引用转换 6.1.4

·         装箱转换 6.1.5

·         隐式常量表达式转换 6.1.6

标准隐式转换特别排除了用户定义的隐式转换。

1.3.2 标准显式转换

标准显式转换包括所有的标准隐式转换以及一个显式转换的子集该子集是由那些与已知的标准隐式转换反向的转换组成的。换言之,如果存在一个从 A 类型到 B 类型的标准隐式转换,则一定存在与其对应的两个标准显式转换(一个是从 A 类型到 B 类型,另一个是从 B 类型到 A 类型)。

1.4 用户定义的转换

C#  允许通过用户定义的转换 (user-defined conversion) 来增加预定义的隐式和显式转换。用户定义的转换是通过在类类型和结构类型中声明转换运算符(第 10.9.3 节)引入的。

1.4.1 允许的用户定义转换

C#  只允许声明某些用户定义的转换。具体而言不可能重新定义已存在的隐式或显式转换。仅当以下条件皆为真时,才允许类或结构声明从源类型 S 到目标类型 T 的转换:

·         ST 是不同的类型。

·         S T 中总有一个是声明了该运算符的类类型或结构类型。

·         S T 都不是 object interface-type

·         T 不是 S 的基类S 也不是 T 的基类。

关于用户定义转换的限制在第 10.9.3 节中有进一步讨论。

1.4.2 用户定义的转换的计算

用户定义的转换将一个值从它所属的类型称为源类型 (source type)转换为另一个类型称为目标类型 (target type)。用户定义的转换的计算集中在查找符合特定的源类型和目标类型的最精确的 (most specific) 用户定义转换运算符。此确定过程分为几个步骤

·         查找考虑从中使用用户定义的转换运算符的类和结构集。此集由源类型及其基类和目标类型及其基类组成(隐式假定只有类和结构可以声明用户定义的运算符,并且不属于类的类型不具有任何基类)。

·         由该类型集确定适用的用户定义转换运算符。一个转换运算符如满足下述条件就是适用的:必须可以通过执行标准转换(第 6.3 节)来使源类型转换为该运算符的操作数所要求的类型,并且必须可以通过执行标准转换来使运算符的结果类型转换为目标类型。

·         由适用的用户定义运算符集明确地确定哪一个运算符是最精确的。概括地讲,最精确的运算符是操作数类型“最接近”源类型并且结果类型“最接近”目标类型的运算符。后面的章节定义了建立最精确的用户定义转换运算符的确切规则。

确定了最精确的用户定义转换运算符后用户定义转换的实际执行包括三个步骤

·         首先如果需要执行一个标准转换将源类型转换为用户定义转换运算符的操作数所要求的类型。

·         然后调用用户定义转换运算符以执行转换。

·         最后如果需要再执行一个标准转换将用户定义转换运算符的结果类型转换为目标类型。

用户定义转换的计算从不涉及一个以上的用户定义转换运算符。换言之,从 S 类型到 T 类型的转换决不会首先执行从 SX 的用户定义转换,然后执行从 XT 的用户定义转换。

后面的章节给出了用户定义的隐式或显式转换的确切定义。这些定义使用下面的术语:

·         如果存在一个从 A 类型到 B 类型的标准隐式转换 6.3.1 ),并且 A B 都不是 interface-type则称 A B 包含 (encompassed by)、称 B 包含 (encompass) A

·         在一个类型集中包含程度最大的类型 (most encompassing type) 是指这样的一个类型它包含了该类型集中的所有其他类型。如果没有一个类型包含所有其他类型,则集中没有包含程度最大的类型。更直观地讲,包含程度最大的类型是集中“最大”的类型,即可将每个其他类型都隐式转换为该类型的一个类型。

·         在一个类型集中被包含程度最大的类型 (most encompassed type) 是指这样一个类型它被该类型集中的所有其他类型所包含。如果没有一个类型被所有其他类型包含,则集中没有被包含程度最大的类型。更直观地讲,被包含程度最大的类型是集中“最小的”类型,即可隐式转换为每个其他类型的一个类型。

1.4.3 用户定义的隐式转换

S 类型到 T 类型的用户定义的隐式转换按下面这样处理

·         查找类型集 D将从该类型集考虑用户定义的转换运算符。此集合由 S如果 S 是类或结构S 的基类如果 S 是类 T如果 T 是类或结构组成。

·         查找适用的用户定义转换运算符集合 U。集合 U 由用户定义的隐式转换运算符组成这些运算符是在 D 中的类或结构内声明的用于从包含 S 的类型转换为被 T 包含的类型。如果 U 为空,则转换未定义并且发生编译时错误。

·         U 中查找运算符的最精确的源类型 SX

o        如果 U 中的所有运算符都从 S 转换 SX S

o        否则SX U 中运算符的合并源类型集中是包含程度最大的类型。如果找不到最直接包含的类型,则转换是不明确的,并且发生编译时错误。

·         U 中查找运算符的最精确的目标类型 TX

o        如果 U 中的所有运算符都转换为 T TX T

o        否则TX U 中运算符的合并目标类型集中是包含程度最大的类型。如果找不到这样的包含程度最大的类型,则转换是不明确的,并且发生编译时错误。

·         如果 U 中正好含有一个从 SX 转换到 TX 的用户定义转换运算符则这就是最精确的转换运算符。如果不存在此类运算符,或者如果存在多个此类运算符,则转换是不明确的,并且发生编译时错误。否则,将应用用户定义的转换:

o        如果 S 不是 SX则执行从 S SX 的标准隐式转换。

o        调用最精确的用户定义转换运算符以从 SX 转换到 TX

o        如果 TX 不是 T则执行从 TX T 的标准隐式转换。

1.4.4 用户定义的显式转换

S 类型到 T 类型的用户定义的显式转换按下面这样处理

·         查找类型集 D将从该类型集考虑用户定义的转换运算符。该类型集由 S(如果 S 为类或结构)、S 的基类(如果 S 为类)、T(如果 T 为类或结构)和 T 的基类(如果 T 为类)组成。

·         查找适用的用户定义转换运算符集合 U。集合 U 由用户定义的隐式或显式转换运算符组成这些运算符是在 D 中的类或结构内声明的用于从包含 S 或被 S 包含的类型转换为包含 T 或被 T 包含的类型。如果 U 为空,则转换未定义并且发生编译时错误。

·         U 中查找运算符的最精确的源类型 SX

o        如果 U 中的所有运算符都从 S 转换 SX S

o        否则如果 U 中的所有运算符都从包含 S 的类型转换 SX 在这些运算符的合并源类型集中是被包含程度最大的类型。如果找不到最直接包含的类型,则转换是不明确的,并且发生编译时错误。

o        否则SX U 中运算符的合并源类型集中是包含程度最大的类型。如果找不到这样的包含程度最大的类型,则转换是不明确的,并且发生编译时错误。

·         U 中查找运算符的最精确的目标类型 TX

o        如果 U 中的所有运算符都转换为 T TX T

o        否则如果 U 中的所有运算符都转换为被 T 包含的类型 TX 在这些运算符的合并源类型集中是包含程度最大的类型。如果找不到这样的包含程度最大的类型,则转换是不明确的,并且发生编译时错误。

o        否则TX U 中运算符的合并目标类型集中是被包含程度最大的类型。如果找不到最直接包含的类型,则转换是不明确的,并且发生编译时错误。

·         如果 U 中正好含有一个从 SX 转换到 TX 的用户定义转换运算符则这就是最精确的转换运算符。如果不存在此类运算符,或者如果存在多个此类运算符,则转换是不明确的,并且发生编译时错误。否则,将应用用户定义的转换:

o        如果 S 不是 SX则执行从 S SX 的标准显式转换。

o        调用最精确的用户定义转换运算符以从 SX 转换到 TX

o        如果 TX 不是 T则执行从 TX T 的标准显式转换。

posted on 2006-08-03 16:05  2017_LIVE  阅读(249)  评论(0编辑  收藏  举报