clr via c#读书笔记四:call、callvirt

1、嵌套类,就是定义在类中的类;嵌套类可以访问外部类的方法、属性、字段而不管访问修饰符的限制,但是外部类只能够访问修饰符为public、internal的嵌套类的字段、方法、属性;

2、CLR如何调用虚方法、属性和事件:

IL提供两个方法调用指令:call和callvirt。

call调用静态方法、实例方法和虚方法;callvirt调用实例方法和虚方法,不能调用静态方法;

call关心的是编译时类型;callvirt关心的是运行时类型;所以,用callvirt调用虚方法时,CLR要调查发生调用的对象的实际类型,为了确定类型,发生调用的变量绝不能是null。

如有两个类:

internal class Person{
    
}
internal class Employee:Person{

}
void main(){
   Person p=new Employee();//p在编译时的类型是Person,而在运行时的类型是Employee
}

call不会检测对象是否为null。而callvirt会检测。所以callvirt指令的执行速度比call指令稍慢。

3、C#用callvirt指令调用所有实例方法。

但是编辑器有时用call而不是callvirt调用虚方法。虽然刚开始有点难以理解,但是以下证明了有时需要这样做:

internal class SomeClass{
    //ToString是基类Object定义的虚方法
    public override String ToString(){
        //编译器使用IL指令'call'
        //以非虚方式调用Object的ToString方法
        //如果编辑器用'callvirt'而不是'call',
        //那么该方法将递归调用自身,直至栈溢出(但是为什么会递归调用自身呢,这里不是base吗,是基类吗?)
        return base.ToString();
    //我的理解:这里实际和reutrn this.ToString()没区别,因为base虽然是基类指针,但是用callvirt时,会检测实际类型,而实际类型就是自身,所有会无限递归调用自身的方法。(不知识这样理解对不对)
  }
}

  

原文地址:https://www.cnblogs.com/yuzhoumanwu/p/8537464.html