概述
1.编译器直接支持的数据类型成为基元类型(primitive type)
。
2.C#语言规范建议使用关键字
,但是作者坚持使用FCL类型名称
。
3.Checked
和Unchecked
基元类型操作:
在对数据类型进行转换时,溢出检查是默认关闭
的。
在CLR中提供了一个特殊IL
指令,如add
指令,不执行溢出检查,而add.ovf(System.OverflowException)
将检查溢出,与之对应的还有sub/sbu.ovf,mul/mul.ovf,conv/conv.ovf
。
在C#中我们使用Checked和Unchecked来检查溢出
Byte b = 100;
b = checked((Byte)(b + 200)); //OverflowException
checked {
...//语句块
}
4.Decimal
在CLR没有对应的IL处理指令。
Decimal
是非常特殊的类型,虽然他在C#、vb
等编程语言中是基元类型,但是在CLR中却没有
能够处理Decimal
的IL
指令,所以Checked
和Unchecked
也就没有意义了。
其提供了一系列public static
方法,如Add,Subtract,Multiply,Divide
以及运算符重载
来完成处理。
所以在编译使用了Decimal
值的程序中,编译器会生成代码来调用Decimal
的成员,并通过这些成员来执行实际运算,这意味着处理速度会慢于其他基元类型。
5.使用引用类型需要留意性能
- 内存必须从托管堆分配。
- 堆上分配的每个对象都有一些额外的成员,这些成员必须初始化。
- 对象中的其他字节(为字段而设)总是设为零。
- 从托管堆分配对象时,可能强制执行一次垃圾回收。
6.任何“类”的类型都是引用类型
,所有值类型
都称为结构
或枚举
。
- 结构:都是抽象类型
System.ValueType
的派生类。 - 枚举:都是抽象类型
System.Enum
的派生类。
而System.ValueType
是System.Object
的派生,并重写了Equals
方法,在两个对象的字段值完全匹配的前提下返回True
,也重写了GetHashCode
方法,使之在生成哈希吗时会将实例字段值考虑在内。
7.对类型实例进行装箱
时发生的事情
- 再托管中分配内存。分配的内存是值类型
各字段
所需的内存量,还要加上托管堆所有对象都有的两个额外成员
(类型对象指针和同步索引块)所需的内存量。 - 值类型的字段分配到新分配的堆内存。
- 返回
对象地址
。现在该地址是对象的引用;值类型成了引用类型。
8.已装箱值类型实例在拆箱
时发生的事情
- 如果包含“对已装箱值类型实例的引用”的变量为
null
,则抛出NullReferenceException
异常。 - 如果引用的对象
不是所需值类型
的已装箱实例,抛出InvalidCastException
异常。
上述二意味着:
Main(){
Int16 x = 5;
Object o = x;
Int32 y = (Int32) o; //出错,InvalidCastException
Int32 y = (Int32)(Int16) o; //应该先拆箱,再转型
}
9.大多数方法进行重载唯一的目的就是减少
常用值类型的装箱次数
。
10.未装箱值类型比引用类型更轻
- 不在托管堆上分配。
- 没有堆上的每个对象都有的额外成员:
类型对象指针
和同步块索引
。
因为未装箱值类型没有同步块索引
,所以不能
让多线程同步访问
实例。
11.值类型可以调用ToString()
方法来避免装箱
struct Point{
private int x,y;
public override string ToString(){
return string.Format("({0}, {1})", x.ToString(), y.ToString());
}
}
Main(){
Point p1;
p1.ToString();
}
调用ToString
方法时p1
不必装箱。表面上看p1
似乎需要装箱,因为ToString
是从基类System.ValueType
继承的虚方法。通常,为了调用虚方法,CLR
需要判断对象的类型来定位类型的方法表。由于p1
是未装箱的值类型,所以不存在类型对象指针。但是JIT编译器
发现Point
重写了ToString
方法,所以会生成代码来直接(非虚地)调用ToString
方法,而不必进行任何装箱操作。
编译器知道这里不存在多态问题,因为Point
是值类型,没有类型
能从它派生以提供
虚方法的另一种实现
。
但是值得注意的是,如果Point
的ToString
方法在内部调用Base.ToString
,那么在调用System.ValueType
的ToString
方法时,值类型的实例会被装箱
。
12.对于object
的equals
方法,它实际上是验证同一性(identity)
,而非相等性(equality)
。
13.检查同一性务必调用ReferenceEquals
,不应该使用==
操作符(除非把两个操作数都转换为object),因为某个操作数的类型可能重载了==
操作符,为其赋予不同于“同一性”的语义。
最后
以上就是清爽八宝粥为你收集整理的【CLR via C#】第5章-基元类型、引用类型和值类型的全部内容,希望文章能够帮你解决【CLR via C#】第5章-基元类型、引用类型和值类型所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复