代码改变世界

CLR via C# 边读边想 04 - 类型基础

2012-06-27 10:59  richardzhaoxb  阅读(136)  评论(0)    收藏  举报

All Types Are Derived from System.Object

运行时要求所有的类型最终都是从 System.Object 继承来的。System.Object 有定义以下的一个公共方法:

  • Equals:判断两个对象的值是否相等。
  • GetHashCode:根据对象的值计算一个哈希值,如果一个类型会被当做key存储在hash table的集合中,那你一定要重写这个方法。
  • ToString:这个大家都知道,默认情况下是返回这个类的全名(this.GetType().FullName),像一些核心类型,比如Boolean,int,就重写了这个方法,输出相应的值,这个方法也经常被用来做调试使用。
  • GetType:返回一个 Type 的对象,这个对象可以被用来做后续的 反射,来得到类中的成员信息。和前面的三个方法不同的是这个方法是不能被重写的。

System.Object 还定义了以下的 protected 方法:

  • MemberwiseClone:这个方法创建了一个新的对象,把之前对象的值一个一个付给新对象的值,并返回新对象的引用。这个方法不能被重写。
  • Finalize:可被重写的方法,当GC决定这个对象是垃圾时,在把这个对象占用的内存回收之前,调用此方法。

CLR 要求所有的创建新对象,都要使用 new 操作符,那使用 new 操作符,系统到底做了哪些事情呢?

  1. 首先,计算这个类型中定义的各个成员需要占用的字节大小,其中包含了他的基类的成员,一直追溯到System.Object类型。所有存放在堆上(heap)的对象都需要一个额外的成员,就是类型对象指针(type object pointer)和同步块索引(sync block index),CLR需要这两个东西来管理对象。
  2. 按照前面计算出来的字节大小从托管堆(managed heap)中分配空间给新的对象,这个被分配的托管堆内存的内容全部被初始化为0。
  3. 初始化类型对象指针和同步块索引。
  4. 调用对象的构造函数,如果类型没有定义构造函数,就调用默认的构造函数。

当所有的事情都完成后,new 操作符返回这个对象的引用。

 

Casting Between Types

在开发中我们经常需要将一个类型的对象,转换为其他类型。CLR 是类型安全的,调用GetType可以知道确切的类型信息。 CLR允许将对象转换到它本身的类型或它的基类型。

另外一种类型转换的方法是 is 操作符,如果能转换的就返回 true,否则返回 false, 所以 is 操作符永远不会报错。例如下面的代码:

1 Object o = new Object();
2 Boolean b1 = (o is Object); // b1 is true.
3 Boolean b2 = (o is Employee); // b2 is false.

如果被转换的对象值是 null,那就永远返回 false。 is 操作符经常被这样使用:

1 if (o is Employee) {
2     Employee e = (Employee) o;
3     // Use e within the remainder of the 'if' statement.
4 }

上面的代码,CLR其实做了两次的类型检查,虽然 CLR 的类型检查性能有所提高,但是毕竟类型检查还是比较消耗性能的,因为经常要追溯整个继承树。所以.Net 就提供了另外一个 as 操作符:

1 Employee e = o as Employee;
2     if (e != null) {
3     // Use e within the 'if' statement.
4 }

as 操作符也不会抛出异常,只是转换不成功就返回null。

 

Namespaces and Assemblies

命名空间是一个逻辑的概率,和实实在在的Assembly不是一一对应的关系,比如说 System.IO.FileStream 是在 MSCorLib.dll 中,而 System.IO.FileSystemWatcher 却在 System.dll 中,甚至连 System.IO.dll 都是没有的。

 

How Things Relate at Runtime

直接看书吧,比较流畅些。P102.