看个简单的例子,只用于演示,不考虑合理性:
1 using System;
2
3 namespace Test
4 {
5     class Program
6     {
7         static void Main(string[] args)
8         {
9             int height = 170;
10             int weight = 60;
11             People.Find();
12             People developer = new Developer()(height, weight);
13             bool isHealthyWeight = developer.IsHealthyWeight();
14             bool isRich = developer.IsRich();
15         }
16     }
17
18     class People
19     {
20         int _height;
21         int _weight;
22
23         public People(int height, int weight)
24         {
25             _height = height;
26             _weight = weight;
27         }
28
29         public virtual bool IsRich();
30
31         public bool IsHealthyWeight()
32         {
33             var healthyWeight = (Height - 80) * 0.7;
34             return Weight <= healthyWeight * 1.1 && Weight >= healthyWeight * 0.9;
35         }
36
37         public static string Find(string id) { return ""; }
38     }
39
40     class Developer : People
41     {
42         public Developer(int height, int weight) : base(height, weight)
43         { }
44
45         public override bool IsRich()
46         {
47             return false;
48         }
49     }
50
51 }

  首先判断类型是否都加载,用到了int,bool,string,这些是在mscorlib.dll程序集的system命名空间下,所以先加载mscorlib.dll程序集,再把int,bool,string加到类型对象里。另外还有我们自己定义的Developer和People,也把类型对象创建好,另外也别忘了基类object,也要加载进来。(实际上还有double啊,这里没画了)另外继承类的类型对象里面都有个字段指向基类,所以才能往上执行到基类方法表里的方法。
  局部变量都在线程栈上,Find()方法是静态方法,直接去People类型对象的方法表里去找,找到后看是否有存根标识,没有的话做JIT编译,有的话直接运行。
  developer的实例化虽然是用People定义的,但实例还是Developer,所以developer的类型对象指针指向Developer,对象里除了类型对象指针还有实例字段,包括基类的。内存分配在托管堆上,并把地址给到线程栈上的变量中。
  虚函数也一样,在运行时已经确定是Developer,所以会调用Developer方法表里的IsRich方法,一样先JIT,再运行。
  以上是一个简单的C#程序的运行过程和在内存上的表现,本篇主要内容来自CLR via C#这本书,小弟算是总结一下,谢谢观看。