Posted on 2008-04-02 23:33
ZelluX 阅读(1538)
评论(14) 编辑 收藏 所属分类:
OOP
这语言真不错,不像Java那么呆,可惜不开源。
入门看的书是CLR via C#中文版,翻译质量不错,起码到现在还没觉得有必要翻一翻原版(不过为什么中文书都喜欢把“栈”叫成“堆栈”呢)。
前面几章粗略看了下,从第四章类型基础开始重点阅读。
继续漫无目的的学习感兴趣的东西,学习之中经常会惊喜的发现,自己看问题的角度已经不同于之前了。
1. 类的new操作会递归调用该类的所有父类构造器,直到System.Object,后者的构造器只是简单返回,用ILDasm查看MSCorLib.dll可以证实这一点。
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
.custom instance void System.Runtime.ConstrainedExecution.ReliabilityContractAttribute::.ctor(valuetype System.Runtime.ConstrainedExecution.Consistency,
valuetype System.Runtime.ConstrainedExecution.Cer) = ( 01 00 03 00 00 00 01 00 00 00 00 00 )
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method Object::.ctor
2. is和as操作符,is类似于Java中的instanceof,as会先检查类型,如果兼容返回该对象的引用,反之返回null。
Emplooee e = o as Employee;
if (e != null) {
// blah
} 利用as可以做到只检验一次对象类型,提高程序性能。这本书的很多地方都提到了性能因素。
3. 方法调用和x86上汇编语言调用机制很类似。先是参数入栈,接着返回地址入栈,返回的时候也差不多。
不知道x64等寄存器较多的架构上会不会使用寄存器传参呢,呵呵。
4. 作为方法的prologue的一部分,CLR会自动将所有局部变量初始化为null或0。
感觉这个自动初始化没什么必要,在第五章可以看到。
SomeVal v1;
SomeVal v1 = new SomeVal(); 这里的SomeVal都是值类型,CLR都会将它们初始化为0。区别在于C#认为前者没有初始化,直接使用这个值会报错;而后者在不赋值的情况下使用这个值。
可能这是CLR和C#之间不统一导致的冗余步骤吧。
5. CLR开始在一个进程中运行时,会给System.Type类型创建一个实例,每个类都会包含指向System.Type类型的指针。
6. CLR提供了执行溢出检查的计算指令,例如add.ovf对应add,mul.ovf对应mul。C#中默认关闭溢出检查。
可以使用checked关键字使用溢出检查。一般情况下,对预计可能发生溢出的代码放到checked块中,对允许溢出的代码(比如计算hash值)放到一个unchecked块中,其他情况,Debug时打开编译器的/checked+开关,Release版本关闭。
7. 所有的值类型都是从System.ValueType继承的。后者重写了Equals方法,比较两个值对象是否完全相等。
8. boxing和unboxing。
boxing:托管堆中分配内存,复制值类型,然后返回对象地址。
unboxing:相当于一个通过指针取值的过程,不过这个指针是已装箱部分中的实际值部分。
9. FCL(Framework Class Library)中包含了支持值类型的泛型容器类,不需要对容器中的元素进行boxing/unboxing处理。
不过这里就有个问题了,值类型的话是放在栈上的,生命周期小于容器的,这个怎么处理呢?第16章才详细解释泛型,先把这个问题留着吧 =,=
10. 依然是性能问题。有时候编译器会反复对一个值类型boxing,此时手动boxing会提高一些性能。
Int32 v = 5;
// 需三次boxing
Console.WriteLine("{0}, {1}, {2}", v, v, v);
// 只需一次boxing
Object o = v;
Console.WriteLine("{0}, {1}, {2}", o, o, o);
接下来书上举了个很搞的例子说明boxing和unboxing的各种情况,其实也很容易理解。