概述:我们常常需要把对象从一种类型转换为另一种类型。
零 类型转换
0.隐式转换
- 只要能保证值不会发生变化,类型转换就可以自动(隐式)进行。
- 有种特殊情况,long/ulong转换为float,这种转换可能会损失数据,但是编译器认为这是一种可以接受的错误。编译器认为只是精度变低了,其值大小不会受影响。
- 派生类转换为基类,是隐式转换。因为派生类必然属于基类。
1.显示转换
- 语法:把强制转换的目标类型名放在要转换的值之前的
()
中。或者使用as
运算符。 - 使用
as
运算符有好处就是,无法转换时候,不会抛出异常;单该运算符只能用于引用类型。 - 基类转换为派生类,是显示转换。基类不一定是派生类的类型。
2.装箱与拆箱–类型转换实例
- C# 值类型存储在栈上,引用类型存储在堆上。
- 装箱(boxing):把值类型转换为引用类型。
- 拆箱(unboxing):把引用类型转换为值类型。
-
装箱是隐式转换,拆箱是显示转换。分析,值类型是派生自System.ValueType,System.ValueType派生自System.Object;所以从基本类型到object(boxing)是从派生类型到基本类型的转换,是隐式的;从object到基本类型(unboxing)是从基类到派生类的转换,所以是显示的。
- 装箱、拆箱之所以重要,装箱太频繁会造成明显性能损失。
int i = 10;
//装箱 是隐式转换,性能影响大
object iObj = i;
//拆箱 是显示转换
var ii = (int)iObj;
一 自定义强制类型转换
0.定义强制类型转换
- 强制类型转换的语法类似于重载运算符。
- 隐式转换
implicit
,显示转换explicit
。
class Person
{
public int Age { get; set; }
public float Height { get; set; }
public static implicit operator float(Person p)
=> p.Height;
public static explicit operator Person(float hegiht)
=>new Person { Height=hegiht};
}
//测试代码
var p = new Person() { Age=10,Height=1.4f};
//隐式转换
var height = p;
//显示转换
var newP = (Person)height;
1.自定义的限制
- 定义不同结构或者类的实例之间的类型强制类型转换(隐式、显示)是完全合法的。但是有限制
- 如果某个类派生自另一个类,就不能定义这连个类之间的类型强制转换(因为这些类型的强制类型转换已经存在了)
- 类型强制转换必须在源数据类型或者目标数据类型的内部定义。
System.Object
->A
->B
->C
System.Object
->A
->B
->D
- 备注:上面这个继承层次中,值有
C
、D
才能自定义类型转换。
2.多重强制类型转换
- 如果在进行要求的数据类型转的时候,C#编译器没有可用的直接强制转换方式,C#编译器就会寻找一种转换方式,把几种强制转换合并起来。
var p = new Person() { Age=10,Height=1.4f};
//隐式转换 类似于 p->float->double
double height = p;