第五章
主要是抽取一些重要的内容,简单的小结
编译语言的基元类型
编译器直接支持的数据类型成为基元类型。
- 基元类型直接映射到framework类库(FCL)中存在的类型。例如:C#的int直接映射到System.int32类型中。
- 编译器能够支持基元类型之间的隐式或显示转型。在不会发生数据丢失的情况下,允许隐式转换;反之,对于数据类型转换后会丢失精度或者数量级,C#就要求显示转换。
- 对基元类型执行的许多算术运算都可能会溢出。C/C++不将溢出视为错误,允许值回滚;VB总是将溢出视为错误,并且在溢出时抛出异常。C#允许程序员自己决定如何处理溢出。
C#全局性地打开或者关闭溢出检查,是使用/checked+编译开关。也可以使用checked和unchecked操作符进行特定区域的溢出检查。
Byte b =100;
b = checked ((Byte) b + 200); //抛出OverflowException异常
b =(Byte) checked(b + 200); //不会抛出异常
使用checked和unchecked语句
checked{
Byte b=4;
b=(Byte)(b+200);
}
引用类型和值类型
1.引用类型必须从托管堆分配。
2.对上分配的每个对象都有一些额外成员,这些成员必须初始化。
3.对象中的其他字节总是设为零。
4.从托管堆分配对象时,可能强制执行一次垃圾回收。
- 值类型的实例一般在线程栈上分配。
- 值类型的实例不受垃圾回收器的控制。
- 所有的值类型都隐式密封,目的是防止将值类型用作其他引用类型或值类型的基类。
- C#中,用struct声明的类型是值类型,用class生命的类型是引用类型。
- 将值类型赋值给另一个值类型变量,会执行逐字段的复制。将引用类型的变量复制给另一个引用类型的变量只复制内存地址。
值类型的装箱和拆箱
- 值类型比引用类类型“轻”,原因是它们不作为对象在托管堆中分配,不被垃圾回收,也不通过指针进行引用。
- 值类型装箱时会发生:在托管堆中分配内存、值类型字段复制到新分配的堆内存、返回对象地址。
- 拆箱不是直接将装箱过程倒过来,拆箱的代价比装箱低得多。拆箱实际就是获取指针的过程。获取装箱对象中各个字段的地址称为拆箱。(获取字段地址之后往往伴随着值的复制,而这个将字段的值从堆复制到栈的过程不在拆箱的概念范畴之内,即拆箱不要求在内存中复制任何字节)
- 在对对象进行拆箱的时候,只能转型为最初未拆箱的值类型
简而言之
装箱:将值类型转换为引用类型。
拆箱:将引用类型转换为值类型
对象哈希码
选择算法来计算类型实例的哈希码时,请遵守一下规则:
- 这个算法要提供良好的随机分布,使哈希表获得最佳的性能
- 可在算法中调用基类的GetHashCode方法,并包含它的返回值,但一般不要调用Object或ValueType的GetHashCode方法,因为两者的实现都与高性能哈希算法不沾边.
- 算法至少使用一个实例字段
- 理想情况下,算法使用的字段应该不可变,也就是说,字段应在对象构造时初始化,在对象生存期"永不改变"
- 算法执行速度尽量快
- 包含相同值的不同对象应返回相同的哈希码。例如,包含相同文本的两个String对象应返回相同哈希码.
dynamic基元类型
-
C#是类型安全的编程语言。意味着所有的表达式都解析成类型的实例,编译器生成的代码只执行对该类型有效的操作。
-
为了方便开发人员使用反射或者与其他组件通信,C#编译器允许将表达式的类型标记为dynamic,还可以将表达式的结果放到变量中。代码使用dynamic表达式/变量调用成员时,编译器生成特殊的IL代码来描述所需的操作。这中特殊的代码成为payload(有效载荷),在运行时payload代码根据dynamic的实际类型来决定具体的执行操作。