编译时(compile-time)和运行时(runtime)CLR
编译时
应用:const、运算符重载、函数重载、类型
工作内容:编译时类型检查(赋值检测)、语法分析、词法分析
静态多态:特色多态(重载、运算符重载)
call调用虚方法的情况
1、call:可调用 静态方法、实例方法、虚方法。call假定该变量不为null
2、call常用于调用值类型的方法或密封的引用的类型、静态方法中
3、密封类型的引用调用虚方法时,采用call调用可以减少callvirt进行类型检查的时间,提高调用性能。
4、值类型调用虚方法时,因为值类型首先是密封的,其次call调用可以阻止值类型被执行装箱。
5、基类调用虚方法时,采用call可以避免callvirt递归调用本身引起的堆栈溢出。常见的覆写例如,实现System.Object的虚方法Equals()、ToString()时,就采用call调用方式。
静态绑定:
早期绑定也称静态绑定,是指编译时绑定;早期绑定对象基本上是强类型对象或静态类型对象。
早期绑定在编译期间识别并检查方法、属性、函数,并在应用程序执行之前执行其他优化。在这个绑定中,编译器已经知道它是什么类型的对象以及它拥有的方法或属性。
AOT
AOT 即Ahead of Time Compilation,即运行前编, 与之对应的是JIT。
运行时
应用:泛型、虚方法、抽象方法、表达式树、dynamic、继承
动态多态:参数多态(泛型)、子类型多态(继承、虚方法、抽象方法)
callvirt调用非虚方法的情况
1、callvirt:可调用实列、虚方法。JIT编译器会生成代码来检测调用方法的对象不为null。
2、callvirt常见于在引用类型中调用非虚方法的情况,其原因是callvirt调用时,如果引用变量为null则会抛出NullReferenceException,而call调用则不会抛出任何异常。为类型安全起见,在C#中会调用callvirt来完成引用类型的非虚方法调用。
动态绑定:
后期绑定也称动态绑定。在后期绑定中,编译器不知道它是什么类型的对象以及它拥有的方法或属性,这里的对象是动态对象。对象的类型是根据它在运行时在右侧保存的数据来确定的。基本上,是通过使用虚拟方法来实现后期绑定。
后期绑定的最大优点是这种类型的对象可以保存对任何对象的引用,但缺少早期绑定对象的许多优点。比如:后期绑定的性能比早期绑定慢,因为它需要在运行时进行查找。
工作内容:
1、JIT检测实列对象是否为NUll
2、CLR加载定义他们的程序集(如果尚未加载)。
3、JIT检测类型和成员引用(多态就是在此时实现的)
4、 GC最终分配内存运行的过程。
运行时类型检查
1、数组是否越界
int[] arr = { 1, 2, 3 }; int result = arr[4]; Console.WriteLine(result);
一编译还是正常通过.但一运行就报错了啊.C#与C++中不同,它有与运行时类型检查.会检查数组是否越界不.如果越界了不会给你返回个错误的结果,而是直接报错.你如果没有异常处理语句处理的话整个软件就挂掉了啊.
2、检测实列对象是否为NUll
public class Program {/*w w w . de mo 2 s .c o m*/ public int IOR = 90; public static void Main() { Object ob= new Object(); ob.GetType().ToString(); Program program = null; Int32 x = program.GetFive();//为什么编译器不保错。 } private int GetFive() { throw new NotImplementedException(); } }
CIL代码中调用方法的常用方法有call和callvirt两种,那它们到底有什么区别呢?
call调用虚方法的情况
1、call:可调用 静态方法、实例方法、虚方法。call假定该变量不为null
2、call常call常用于调用 值类型的方法或密封的引用的类型、静态方法中
callvirt调用非虚方法的情况
1、callvirt:可调用实列、虚方法。JIT编译器会生成代码来检测调用方法的对象不为null。
2、callvirt常见于在引用类型中调用非虚方法的情况,其原因是callvirt调用时,如果引用变量为null则会抛出NullReferenceException,而call调用则不会抛出任何异常。为类型安全起见,在C#中会调用callvirt来完成引用类型的非虚方法调用。
区别
call指令调用静态类型、声明类型的方法,而callvirt调用动态类型、实际类型的方法。万变不离其宗,这条规则就是call指令与callvirt指令骨子里的区别。