C# 隐式转换
下面几种类型的转换被称之为隐式转换
- 同一性转换
- 隐式数值转换
- 隐式枚举转换
- 隐式引用转换
- 包装转换
- 隐式常数表达式转换
- 用户自定义隐式转换
隐式转换可以在很多种情况下发生,包括函数子句调用,cast计算表达式和赋值语句。
预定义的隐式转换总会成功而且不会引发异常,适当合理的用户自定义隐式转换也可以展示出这些 特性。
一. 同一性转换
同一性转换把任何类型转换为统一的类型。只有在所需转换的实体可以被转换到一种特定的类型时才可以进行同一性转换。
二. 隐式数值转换
隐式数值转换可以在下面类型中发生:
• 从 sbyte 到 short, int, long, float, double 或 decimal。
• 从 byte 到 short, ushort, int, uint, long, ulong, float, double 或 decimal。
• 从 short 到 int, long, float, double 或 decimal。
• 从 ushort 到 int, uint, long, ulong, float, double 或 decimal。
• 从 int 到 long, float, double 或 decimal。
• 从 uint 到 long, ulong, float, double 或 decimal。
• 从 long 到 float, double 或 decimal。
• 从 ulong 到 float, double 或 decimal。
• 从 char到 ushort,int,uint, long, ulong, float, double 或 decimal。
• 从 float到 double。
从 int,uint,long到float以及从long到double类型的转换可能会造成精度的损失,但并不会造成数量上的损失。除此之外的其他隐式数值转换不会损失任何信息。这里不存在转到 char类型的隐式数值转换,也就是说其他的整型数据不会被自动地转换为字符型数据。
三. 隐式枚举转换
一个隐式枚举转换允许小数-整数实字(decimal-integer-literal)被转换成任意的枚举类型。
四. 隐式引用转换
隐式 reference转换可以在下面类型之间发生:
• 从任意 引用类型 到对象 。
• 从任意 类类型 S 到任意 类类型 T, 只要 S 是由 T 派生出来的。
• 从任意 类类型 S 到任意 接口类型 T, 只要 S 实现 T。
• 从任意 接口类型 S 到任意 接口类型 T, 只要 S 是由 T 派生出来的。
• 从一个带有元素类型 S 的 数组类型 S 到一个带有元素类型 T 的 数组类型 T,只要下述各项均成立:
• S 和 T 只是元素类型不同。换句话说,S 和 T 有相同的维度。
• SE 和 TE 都是 引用类型 。
• 存在从 SE 到 TE 隐式引用转换。
• 从任意 数 组类型 到 System.Array。
• 从任意 代 表类型 到 System.Delegate。
• 从任意 数 组类型 或 代表类型 到 System.Icloneable。
• 从 null类型到任意 引用类型 。.
隐式引用转换指的是在引用类型间肯定可以成功的类型转换,它们是不需要实时检测的。
引用转换,不管是显式或是隐式的都不会改变被转换对象的引用一致性。换句话说,当引转换发生时,它并未改变被转换对象的数值。
五. 包装转换
包装转换允许任何数值类型被隐式地转换为类型对象,或者任何由这个数值类型实现的接口类型。 包装一个数值类型的数值包括分配一个对象实例并且将数值类型的数值复制到实例当中。
包装数值类型的数据的实际过程,可以通过想像一个对那种类型的包装类的实际例子来解释。对于数值类型 T,包装类要按下面定义:
class T_Box
{
T value;
T_Box(T t)
{
value = t;
}
}
对于类型 T的数值 v的包装现在由执行表达式 T_Box(v)来代替,并且返回类型为 object的结果实例。这样,语句
int i = 123;
object box = i;
从概念上符合
int i = 123;
object box = new int_Box(i);
如上面的 T_Box 和 int_Box 的包装类型实际不存在,而被包装数据的动态类型实际上并不是一个类类型。作为替代,类型T 的一个被包装的数据有动态类型T,而使用 is 操作符的动态类型检查可以很方便地引用T。例如
int i = 123;
object box = i;
if (box is int) {
Console.Write("Box contains an int");
}
将在控制台输出字符串 “Box contains an int”。
包装转换隐式地把被包装的数据进行了备份。这与从引用类型到object类型的转换不同,在那里数据一直引用相同的实例,并被认为几乎不从类型 object派生。例如,给出声明
struct Point
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
下面的语句
Point p = new Point(10, 10);
object box = p;
p.x = 20;
Console.Write(((Point)box).x);
因为在发生把 p赋值给 box的隐含包装操作时,p被拷贝,所以将在控制台上输出数值 10。如果Point被声明为一个类,因为p和box将引用相同的实例,就会输出20。
六. 隐式常数表达式转换
常量表达式的类型可以是以下类型之一:sbyte、byte、short、ushort、int、uint、long、ulong、 char、float、double、decimal、bool、string、枚举类型或空(null)类型。
隐式常数表达式转换允许下列类型的转换:
- 整型常数表达式可以被转换成为 sbyte,byte,short,ushort,uint或者 ulong类型,只有这个整型常数表达式的数值未超出目标类型的取值范围就行。
- 一个 long类型的常数表达式可以被转换成为 ulong类型,只有这个常数表达式的取值非负就行。