编译时(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指令骨子里的区别。

 

posted @ 2021-10-25 01:49  小林野夫  阅读(519)  评论(0编辑  收藏  举报
原文链接:https://www.cnblogs.com/cdaniu/