1.编译
C#源代码文件 --C#编译器--> 托管模块 ----> 程序集
1).托管模块:又称PE文件,一个托管模块由4部分构成:
PE32(+)头,标准 Windows PE 文件头;
CLR头,包含了使这个模块成为托管模块的信息;
元数据,元数据中主要有两种类型的表:一种类型的表描述的是源代码中定义的类型和成员(即定义表),另一中类型的表描述的是源代码中引用的类型和成员(引用表),还可能包含清单表(假如该模块是程序集的主模块);
IL代码,编译器编译源代码时生成的代码。运行时,CLR将IL编译成本地CPU指令;
2).程序集:是一个或多个模块或资源文件的逻辑性分组。其次程序集是重用,安全性以及版本控制的最小单元。
程序集中可以包含一个托管模块或多个托管模块,这就取决于对编译器或工具的选择,C#编译器默认生成的是只含有一个托管模块的程序集。
如果程序集包含多个托管模块,那么其中有一个元数据中包含清单的模块就是程序集的主模块,它要么是一个exe文件,要么是一个dll文件;
如果程序集只包含一个托管模块,那么该模块的元数据中就包含清单表,其实这个模块就代表了程序集;
也就是说一个程序集的必须包含一个主模块,至于那个模块是主模块是由清单表的所在位置决定的;
3)清单表:清单表主要记录了作为程序集的组成部分的那些文件(这些文件包括托管模块和资源文件)。
2.运行
1).Windows 检查exe文件头 也就是PE32(+)头,根据这个头信息决定创建32为,64位,还是Wow64进程,然后初始化堆;
2).在进程的地址空间中加载对应版本的mscoree.ddl文件;
3).加载mscorlib.dll文件,并为其定义的System.Type类型创建一个特殊的对象,放到堆上;
4).主线程(线程的栈已经开辟好了)调用mscoree.dll中定义的一个方法加载CLR(主要负责内存管理,程序集加载,安全性,异常处理,线程同步等);
5).加载exe程序集,然后根据程序集的CLR头找到入口方法Main(),随即,托管应用程序开始执行;
3.执行方法
1).如果方法有参数首先传递传输
2).编译方法(如果方法还为编译),这时会查找出方法引用到的所有的类型,如果这些类型的数据结构还未创建,就创建这些类型的类型对象,如果这些类型是其他程序集中定义的就先加载这些程序集,然后根据这些程序集创建中的元数据信息创建这些类型的数据结构即类型对象;
3).执行方法