1.CLR最重要的特性之一就是类型安全:
在运行时,CLR总是知道对象的类型是什么,调用GetType()方法即可知道对象的确切类型。这也就是为什么GetType()方法是基类Object中的非虚方法,因为如果可以重写GetType()方法,那么他返回的就不一定是当前的对象类型,违背了类型安全。
2.使用 is 和 as 操作符来转型:
is和as在任何情况下都不会抛出异常。
public class People{}
public class Student : People{}
在做类型判断时,我们可以使用is操作符
var p = new People();
var s = new Student();
Console.WriteLine($"{p is People}\t{p is Student}\t{s is People}\t{s is Student}");
// True False True True
在做类型转换时,使用as操作符
// Use is
if(s is People) var pp = (People)s;------------①
// Use as
var pp = s as People;--------------------------②
值得注意的是
①中在if中判断一次后,使用强制转换时CLR会再判断一次是否兼容,如果不兼容那么转换就会报错,所以在①中一共有两次判断。
②中有且只有CLR来判断一次,并且在不兼容的情况下,会返回null而不会抛出异常。
所以我们在转化类型时,应该使用as操作符,不仅性能高而且还安全。
3.命名空间和程序集的关系:
命名空间和程序集(实现类型的文件)不一定相关。特别是,在同一命名空间的类型可能在不同的程序集中实现。例如:在同一命名空间System.IO下的FileStream类型和FileSystemWatcher类型,其中FileStream在MSCorLib.dll程序集中实现,而FileSystemWatcher在System.dll程序集中实现。
当然,同一个程序集也包含不同命名空间中的类型。
4.线程栈:
已加载CLR的一个Windows进程可能有多个线程,在线程创建时分配到1MB的栈,栈空间用于向方法传递实参,方法内部定义的局部变量也在栈上。
5.线程执行一个方法:
一个简单的方法包含
序幕(prologue)代码,在方法开始时工作前对其进行初始化,对方法内的局部变量分配内存,CLR对其变量初始化。尾声(epilogue)代码,在方法完成工作后对其进行清理,以便返回至调用者。
6.堆上所有的对象都包含两个额外成员:
类型对象指针(Type Object Pointer),任何时候在堆上新建对象,CLR都自动初始化内部的“类型对象指针”成员来应用和对象对应的类型对象。同步块索引(Sync Block Index),在调用类型的构造器(本质上是可能修改某些实例数据字段的方法)之前,CLR会先初始化同步块索引,并将对象的所有实例字段设为null或0
7.CLR创建类型对象时,必须初始化以上两个成员
我们在创建实例时
Student Hao = new Student();
Student Sin = new Student();
Teacher Jax = new Teacher();
在堆上如下

值得注意的是类型对象(Student、Teacher)本质上也是对象,它们的类型对象指针也必须初始化。事实上CLR开始在一个进程中运行时,会立即为MSCorLib.dll中定义的System.Type类型创建一个特殊的类型对象,而Student、Teacher类都是他的实例,所以结果如下

当然Type类型对象也有自己的类型对象指针,他指向自己。
所以现在我们知道了,System.Object的GetType方法返回存储在指定对象的类型对象指针成员中的地址,也就是说,GetType方法返回指向对象的类型对象指针。
这样就可以判断系统中的任何对象了。
下面的运行结果可以验证

1025

被折叠的 条评论
为什么被折叠?



