本章概述
1.1 将源代码编译成托管堆
CLR的核心功能(比如内存管理、程序集加载、安全性、异常处理和线程同步)可由面向 CLR 的所有语言使用。
托管模块:是一个标准的32位 Microsoft Windows可移植执行体(PE32)文件,或者是一个标准的64位Windows可移植执行体(PE32+)文件。它们都是需要CLR才能执行。(如图)
元数据 : 是一组数据表。其中一些数据表描述了模块中定义的内容,比如类型及其成员。
元数据用途:
1. 编译时,元数据消除了对本地C/C++头和库文件的需求,因为在负责实现类型/成员的IL代码文件中,已包含和引用的类型/成员有关的全部信息,编译器可直接从托管模块中读取元数据。
2. Microsoft Visual Studio 使用元数据帮助你写代码。它的“智能感知”(IntelliSense)技术可以分析元数据,指出一个类提供了哪些方法、属性、事件、字段。
3. CLR 的代码验证过程使用元数据确保代码只执行“类型安全”的操作。
4. 元数据允许一个对象的字段序列化到一个内存块中,将其发送给另一台机器,并从元数据知道那个对象中的哪些字段引用了其他对象。
5. 元数据允许垃圾回收器跟踪对象的生存期。垃圾回收器能判断任何对象的类型,并从元数据知道那个对象中的哪些字段引用了其他对象。
1.2 将托管模块合并成程序集
![](https://img-my.csdn.net/uploads/201210/25/1351173819_1487.jpg)
1.3 执行程序集的代码
1.3.1 IL和验证
IL是基于栈的,这意味者它的所有指令都要将操作数压入(push)一个执行栈,并从栈弹出(Pop)结果。由于IL没有提供操作寄存器的指令,所以人们可以很容易的创建新的语言和编译器,生成面向CLR的代码。
IL指令还是“无类型”的。
1.3.2 不安全的代码
C# 编译器默认生成的是安全的(safe)代码,这种代码是否安全是可以验证的。然而C#编译器也允许开发人员写不安全的(unsafe)代码。不安全的代码允许直接操作内存地址。并可操作这些地址处的字节。这是一个非常强大的功能,通常只有在与非托管代码进行互操作,或者在提升对效率要求极高的算法性能的时候,才需要这样做。
使用不安全的代码会带来一个重大风险,这种代码可能会破坏数据结构,危害安全性,甚至可能造成新的安全漏洞。因此C#编译器要求包含不安全代码的方法都要用unsafe关键字标记。除此之外,C#编译器还要求使用/unsafe开关来编译源代码。
1.4 本地代码生成器:NGen.exe
NGen.exe可以在一个应用程序安装到用户的计算机上时,将IL代码编译成本地代码。
NGen.exe能在一下两种情况下发挥重要作用:
1. 加快引用程序的启动速度, 运行NGen.exe 能加快启动速度,因为代码已经编译成本地代码,运行时不需要在进行编译。
2. 减小应用程序的工作集, 如果一个程序集会同时加载到多个进程中,对该程序集运行MGen.exe 可减少应用程序的工作集。NGen.exe会将IL编译成本地代码。
更多信息参考官方文档,这里就不赘述了.http://msdn.microsoft.com/zh-cn/library/6t9t5wcf.aspx
1.5 Framework 类库
.Net Framework 中包含了Framework类库(Framework Class Library,FCL)。FCL是一组DLL程序集的统称,其中含有数千个类型定义,每个类型都公开一些功能。
我们可以利用这些程序集创建的一部分应用程序。比如(web 服务、web窗体应用程序、Windows应用程序、windows服务、组件库等等)
1.6 通用类型系统(CTS)
CLR完全是围绕类型展开的,这一点到现在为止应该是很明显了。通用类型,用一种编程语言写的代码能与用另一种语言写的代码沟通,由于类型是CLR的根本,所以Microsoft 指定了一个正式的规范,即“通用类型系统”(Common Type System,CTS),它描述了类型的定义和行为。
CTS 规范规定,一个类型可以包含零个或者多个成员。比如 (字段、方法、属性、事件等),除此之外,CTS还为类型继承、徐方法、对象生存期等定义了相应的规则。其实没有必要专门学习CTS规则,因为你选择的语言会采用你熟悉的方式公开它自己的语言语法和类型规则。
CTS另一个规则:所有类型最终必须从预定义的System.Object类型继承。可以看出Object是System命名空间中定义的一个类型名称。Object是其他所有类型的根,因此每一个实例都有一组最基本的行为。
a. 比较两个实例的相等型
b. 获取实例的哈希码
c. 查询一个实例的真正类型
d. 执行实例的浅(按位)拷贝
f. 获取实例对象的当前状态的一个字符串表示。
1.7 公共语言规范(CLS)
我们看一下CTS的规则:在CLR中,一个类型的每个成员要么是一个字段(数据),要么是一个方法(行为),这意味着每一种编程语言都必须能访问字段和调用方法。为了方便的进行编程,语言通常提供了额外的抽象,对这些常见的编程模式进行简化。例如,数组、属性、索引器、委托、事件、构造器、析构函数、操作符重载等概念。
如下一个类
using System;
namespace ConsoleApplication1
{
internal sealed class Test
{
// 构造器
public Test() { }
// 析构器
~Test() { }
// 操作符重载
public static Boolean operator ==(Test t1, Test t2)
{
return true;
}
// 重载"=="必须重载"!="
public static Boolean operator !=(Test t1, Test t2)
{
return false;
}
// 一个操作符的重载
public static Test operator +(Test t1, Test t2)
{
return null;
}
// 属性
public String Aproperty
{
get { return null; }
set { }
}
// 索引器
public String this[Int32 x]
{
get { return null; }
set { }
}
// 事件
event EventHandler AnEvent;
}
}
编译器编译上述代码会得到一个类型,其中包含大量的字段和方法。可以使用反汇编工具IL(ILDasm.exe)来检查最终生成的托管模块。
下面看看IL中显示的Test类型字段和方法。
分别简单说下Test的字段和方法,由于比较多,我就随便说几个重要的。
AnEvent 字段 事件,字段名是AnEvent,类型是System.EventHandler,从上图可以看出这是唯一的一个字段。
.ctor 类型为方法,构造器.红色的正方快代表方法。
add_AnEvent方法 是 AnEvent的add访问器方法
get_Aproperty方法是 Aproperty属性的get访问器,对应还有set_Aproperty是set访问器。
op_Addition 方法是+操作符.
------------------------------------------------------------------------------------------------------------------
注:CLR的执行模型基本就写完了,热烈欢迎大家讨论,转载和分享。