基类型
之前有过这样的疑惑:int 和System.Int32有什么不同?实际上System.Int32是再FCL中的定义,多数编译器对于此等类型都有自己的定义,他们和FCL中的定义自动建立映射关系。如C#中System.Int32就映射为int.
所以我们可以很方便的用int i=10进行定义,实际上编译为IL后,可以看到其以Int32的映射出现。
FCL中的类型在C#都有对应的基元类型,但是在CLS中却不一定有,如Sbyte,uint等。
特别要注意的是:类型转换时,如果大范围向小范围类型转换,需要强制转换,编译器将做截断处理;反之,可以安全的隐式转换。
Single s2 = 6.8F;
Console.WriteLine((int)s2); //output:6
Checked/UnChecked
此关键字,用来对表达式或语句块进行安全性检查。判断运算是否有溢出产生。
在IL中,每个运算符(+,-,*,/)都对应一对指令,如+对应Add和Add.ovf。调用后者时,将进行溢出检查。
这样,我们在使用此关键字时,实际上调用了IL中对应的指令而已。
溢出检查动作将使得应用程序性能受到影响。
值类型和引用类型
1.结构体和枚举类型属于值类型,其余都为引用类型。
2.引用类型存储在托管堆上,同时需要存储额外的信息,受GC的控制。
3.值类型存储在线程栈中,不受GC控制,出了作用域,自动释放。
4.值类型的赋值和传递,需要进行字段的复制和存储,而引用类型只传递指针。
通常在作为参数传递和作为返回值传递时,如果数据过大,不易用值类型。
装箱和拆箱
值类型有两种状态:装箱状态和拆箱状态;引用类型只有一种:装箱状态。
通常当值类型作为参数传递时,而接受参数方接受参数类型为引用类型时,将发生装箱作业。
装箱时:
1.在托管堆分配值类型字段需要的内存,同时还要为附加信息分配空间(类型对象指针,同步块索引)。
2.数值copy至堆中
3.返回存储指针
可见,装箱作业是非常消耗性能的。所以我们在写程序过程中,应当尽可能避免装箱情况的出现。net2.0出现的泛型,实际上一方面的原因就在于此。
如:Console.WrileLine(12+"test")---> Console.WriteLine(12.ToString()+"test");之间的性能可测试。
拆箱时:
1.获取已装箱对象的各个字段的地址。
2.将这些字段包含的值从堆中复制到基于堆栈的值类型实例中。
引用变量如果为null,拆箱时抛出NullRefernceException异常;拆箱时如果不能正确转型,则抛出InvalidCastException异常。
装箱之前是什么类型,拆箱时也要转成该类型,转成其基类或子类都不行。