【CLR via C#】第5章-基元类型、引用类型和值类型

1.编译器直接支持的数据类型成为基元类型(primitive type)
2.C#语言规范建议使用关键字,但是作者坚持使用FCL类型名称
3.CheckedUnchecked基元类型操作:

在对数据类型进行转换时,溢出检查是默认关闭的。
在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中却没有能够处理DecimalIL指令,所以CheckedUnchecked也就没有意义了。
其提供了一系列public static方法,如Add,Subtract,Multiply,Divide以及运算符重载来完成处理。
所以在编译使用了Decimal值的程序中,编译器会生成代码来调用Decimal的成员,并通过这些成员来执行实际运算,这意味着处理速度会慢于其他基元类型

5.使用引用类型需要留意性能
  • 内存必须从托管堆分配。
  • 堆上分配的每个对象都有一些额外的成员,这些成员必须初始化。
  • 对象中的其他字节(为字段而设)总是设为零。
  • 从托管堆分配对象时,可能强制执行一次垃圾回收。
6.任何“类”的类型都是引用类型,所有值类型都称为结构枚举
  • 结构:都是抽象类型System.ValueType的派生类。
  • 枚举:都是抽象类型System.Enum的派生类。

System.ValueTypeSystem.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是值类型,没有类型能从它派生以提供虚方法的另一种实现
但是值得注意的是,如果PointToString方法在内部调用Base.ToString,那么在调用System.ValueTypeToString方法时,值类型的实例会被装箱

12.对于objectequals方法,它实际上是验证同一性(identity),而非相等性(equality)
13.检查同一性务必调用ReferenceEquals,不应该使用==操作符(除非把两个操作数都转换为object),因为某个操作数的类型可能重载了==操作符,为其赋予不同于“同一性”的语义。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值