CLR via C#笔记 - 第四章

所有类型都从System.Object派生

  • “运行时”要求所有类型都从System.Object派生
  • 所有对象都用new操作运算符创建。
  • 没有和new操作符对应的delete运算符。不能显式释放对象。

类型转换

  • 运行时,CLR总是知道对象是什么类型。
  • CLR允许对象隐式向上转型,显式向下转型。
  • 在运行时,CLR检查转型操作,如果转换的类型不是对象的实际类型或者基类,那么会抛出InvalidCastException异常。
  • is操作符检查对象是否兼容于指定类型。但是这样效率特别低,因为CLR检查了两次对象类型, is操作符检查了一次,内部转型又检查了一次
if( o is Employee){
    Employee e = (Employee) o;
    // use e
}
  • as运算符简化了代码的写法,还提升了性能(只检查一次对象类型)。如果对象不能转型,则返回值为null。如果直接使用null赋值的引用,会抛出异常System.NullReferenceException。
Employee e = o as Employee;
if( e != null){
    // use e
}

命名空间和程序集

  • CLR对“命名空间”一无所知。访问类型时, CLR需要知道类型的完整名称以及该类型的定义在哪个程序集中。
  • 检查类型定义时,编译器在 /reference 选项指定的程序集中检查。编译器扫描所有引用的程序集,查找类型定义,将程序集信息和类型信息嵌入到元数据中。
  • 命名空间和程序集不一定相关。同一命名空间的类型可能在不同程序集中出现,反之亦然。

运行时的相互关系

  • 线程创建的栈的大小默认为1MB (可以修改)
void M3(){
 Employee e;
 Int32 year;
 e = new Manager();
 e = Employee.Lookup("Joe");
 year = e.GetYearsEmployed();
 e.GetProgerssReport();
 }

JIT编译器将M3的IL代码转换为CPU指令时,先根据M3内部引用的所有类型确认所有程序集已经加载,即Employee , Int32, Manager 以及String(因为”Joe”)。然后利用元数据,CLR提取类型有关的信息,创建一些数据结构表示自身,(创建类型对象,即Type类型实例化的对象),但没有编译函数。
然后再执行代码创建一个Manager对象。该对象也有类型对象指针和同步索引块,以及包含必要的字节容纳Manager类型定义的所有实例数据字段,以及任何基类的实例字段。

  • 堆上的对象都有两个额外的成员:类型对象指针和同步块索引。类型对象指针指向该对象的类型。即 e = new Manager(); e中的类型对象指针会指向Manager类型对象(Type类型实例化的对象),Manager类型对象中的类型对象指针指向 Type类型对象,Type类型对象指向自身。
  • 虽然CLR会自动将所有局部变量初始化为null或0,但是如果代码试图访问未显式初始化的局部变量,C#会报告错误消息: 使用了未赋值的局部变量
  • 调用静态方法时,CLR先定义静态方法的类型,然后在该类型的方法表中查找方法,对方法编译。
  • 调用非虚实例方法,JIT会回溯类层次结构,在每个类中查找方法,并编译。
  • 调用虚实例方法时,JIT先确认变量类型(使用类型对象指针),再在类型对象方法表中查找被调用的方法,并编译。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值