Pulpcode

捕获,搅碎,拼接,吞咽

0%

C#类型转换

这里总结c#类型转换的知识

值类型

值类型的类型转换,可以理解为用一个类型A的值去初始化一个类型B的变量。

变宽转换

如果是变宽转换,那么不会有问题。比如32位的int到64位的int,或者是int到float。

变窄转换

如果是变窄转换,那么就可能有问题。(可能会发生溢出)

首先,变窄转换是需要强制类型转换的,不能像隐式转换那样,需要在括号中写入要转换的类型。

1
2
double foo = 3.5;
float bar = (float)foo;

溢出

比如short可以存储0~32767的数字,而byte可以存储的最大值是255,那么你将一个为7的short转换为byte类型,那么不会有什么问题。但是如果你将一个大于255的short强制类型转换为byte,那就会有问题。

1
2
3
4
5
byte destinationVar;
short sourceVar = 281;
destinationVar = (byte)sourceVar;
// sourceVar val: 281
// destinationVar: 25

原因是这样的(源数据的最左边一位丢失了):

281 = 100011001
25  = 000011001
255 = 011111111

这个数值的例子摘自《c#经典入门》

可以使用checkedunchecked关键字检验溢出。

checked(<expression>)
unchecked(<expression>)

默认就是unchecked的,不写这个关键字也行。如果是checked,而且发生了溢出,就会抛出异常。

引用类型

引用类型的转换与值类型“看上去有点相反”。

首先要明确的是引用类型转换的是栈中的变量,而该变量指向的位于堆中的对象不受影响。

向上转换

将父类的引用指向子类对象是没什么问题的(多态的本质)

向下转换

与值类型的转换类似,引用类型的向下转换也会用到强制类型转换。

而这种转换并不总是有效(即便是基类到派生类的转换),转换是否成功,只有在运行的时候才会知道。

1
Child child = (Child)father;

最常见的用法是传递object对象,然后在将这个得到的对象转化为要处理的类型,(非泛型集合,发送消息机制)

as运算符

强制类型转换出现错误会抛出异常,使用asis会更加优雅。

as运算符用于在两个引用类型之间转换,转换失败后会返回一个null,并不会抛出异常。

1
2
3
4
5
6
ClassA a = new ClassA();
ClassB b = a as ClassB;
if(b != null)
{
......
}

也可以使用is来判断是否可以转换,如果可以再使用强制类型转换。

1
2
3
4
5
Class a = new ClassA();
if(a is ClassB)
{
Class b = (ClassB)a;
}

无论是as还是is运算符,都比直接使用强制类型转换要安全,而且不需要使用异常检查,只需要判断结果是否为空就可以了。

类型无关的类型转换

之前提到的引用类型转换,是指相关类型之间的转换,比如继承关系,共享接口。

不相关的两个类型,也可以发生类型转换,这就要使用到重载运算符,你需要自己定义内部转换的原理。

需要使用到的重载运算符有: implicit(隐式类型转换) explicit(显示类型转换)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 定义ConvClassA到ConvClassB的隐式转换
public class ConvClassA
{
public static implicit operator ConvClassB(ConvClassA op)
{
......
}
}

// 定义ConvClassB到ConvClassA的显式转换
public class ConvClassB
{
public static explicit operator ConvClassA(ConvClassB op)
{
......
}
}