雁过请留痕...
代码改变世界

《CLR via C#》笔记——类型基础

2011-06-01 16:25  xiashengwang  阅读(302)  评论(0编辑  收藏  举报

一.所有类型都是从System.Object派生。

 

1,下面两种类型定义完全一致:

//隐式派生自Object

Class Employee{

...

}

//显示派生自Object

Class EmployeeSystem.Object{

}

2System.Object的主要公共成员

Equals:两个对象完全相同,返回true

GetHashCode:返回对象值的Hash码,当对象要在一个Hash表中作为Key使用时,必须重写这个方法。

ToString:默认返回类型的完整名称(this.GetType().FullName),这个方法在继承类中经常都会被重写,如Int32BooleanToString理论上应识别与调用线程关联的CultrueInfo,并相应的采取操作,如:DateTimeToString在不同的CultrueInfo下可能表现出不同的形式。

GetType:返回Type派生的那个对象的实例,指出GetType的那个对象是是什么类型。

 

3System.Object的私有成员

MemberwiseClone:这个非虚方法(也就是该方法不能被重写)能创建类型的一个新实例,新对象的实例字段与this对象的实例对象完全一致。

Finalize:在垃圾回收判断该实例应被垃圾回收之后,在内存被垃圾回收之前会调用这个虚方法(可以在派生类中重载)。

4New关键字

Employee e = new Employee”ConstructorParam”

New主要做了以下几件事:

计算类型极其基类型(一直到System.Object,虽然它没有定义实例字段)中定义的实例字段所需的字节数。堆上的每个对象还需要一些额外的成员,即类型对象指针(type object pointer)和同步块索引(sync block index)。这些额外的成员会计入对象的大小。

从托管堆中分配指定类型要求的字节数。所有字节都设为零(0)。

初始化对象的类型对象指针和同步块索引。

调用类型的实例构造器。大多数编译器都在构造器中生成代码来调用基类的构造器。

 

 

二.类型转换

1CLR最重要的特性之一就是类型安全。调用GetType方法,总是知道一个对象的具体类型是什么。GetType方法是非虚方法,不允许重写。这样就保证了类型的明确性。

2,isas操作符

       is总是返回truefalse

       Boolean b = o is Object

       As 与强制转换一样,但它不会抛出异常。不能转换时,结果为null

       Employee e = o as Employee

 

 

三.命名空间和程序集

1,命名空间是对相关类型的逻辑分组。通过使用using关键字引用命名空间,可以减轻代码的书写量。

2,编译器编译时,会利用using指令为类型加上不同的前缀,直到找到一个完全的匹配项。

3,当不同命名空间的两个类型名称相同时,应使用完全限定名。MyNameplace.ClassA,

YourNameplace.ClassA

4,using指令支持为类型和命名空间创建别名。

Using MyClassA = MyNameplace.ClassA

Using YourClassA = YourNameplace.ClassA

5,最顶级的命名空间应使用本公司的全名。如:Microsofe.VB

6,命名空间和程序集不一定是相关的,相同的命名空间可能在不同的程序集中实现。

 

 

四.运行时的相互联系

1,在一个进程中,可能有多个线程。一个线程创建时,会分配一个1MB大小栈。这个栈空间用于向方法传递实参,并用于方法内部定义的局部变量。栈是由高位内存地址向地位内存地址分配的。

2,CLR会创建一些数据结构来描述类型本身。这叫做类型对象,注意不是对象。类型对象中包含类型对象指针,同步块索引,静态字段,还有紧接着的一个方法表。类型对象本质上也是一种对象,它的类型对象指针应该指向哪里呢?CLR在初始化的时候会创建一个System.Type的特殊类型对象。其他的类型对象创建时,类型对象指针都指向了System.Type。而System.Type的类型对象指针则指向了它自己。

3,当用New创建一个对象时,会在堆上创建这个对象的实例。其中包括类型对象指针,同步块索引,对象及其基类的实例字段。CLR会自动初始化类型对象指针,让它引用与对象对应的类型对象。此外,CLR会首先初始化同步块索引,并对对象的所有字段设为Null0,再调用类型的构造器。New会返回对象的内存地址,该地址存储在线程栈中。

4,调用非虚方法。Jit编译器会找到“发出调用的那个对象的类型”对应的类型对象。如果类型对象中没有被调用的那个方法,Jit会回溯类层次结构(一直回溯到System.Object),并在沿途的类型中查找该方法。之所以能这样回溯,是因为每一个类型对象都有一个字段引用了它的基类型。

5,调用虚方法。Jit编译器需要在虚方法中生成一些格外的代码,方法每次调用都会执行这些代码。代码首先检查发出调用的变量,并更随地址来到发出调用的对象,根据对象的类型对象指针找到类型对象。代码在类型对象的方法表中查找被调用方法的记录项。对方法进行Jit编译(如果需要的话)。