在上一篇.NET CIL第一篇:CIL介绍和入门中我们简要介绍了CIL编程的本质,和学习CIL编程的价值。还介绍了CIL的指令、特性和操作码。接下来的文字中会频繁出现:指令、特性、操作码这些关键字。所以请确定你已经知道它们的含义了。
入栈和出栈:CIL基于栈的本质
像C#这样的高级.NET语言,总是试图尽量隐藏底层的实现。.NET开发一个不太为人注意的方面就是CIL实际上是一个完全以栈为基础的开发语言。回忆我们熟悉的System.Collections命名空间中的Stack类型的功能,它被用于压一个值入栈,同时也能将栈顶的值弹出以供使用。当然,CIL开发人员不是使用System.Collection.Stack来实现入栈和出栈的,不过从思路上是相通的。
正式地说,在CIL中用来负责这个栈实现的部分叫做虚拟执行栈(virtual execution stack)。从下面的介绍中,你将看到CIL提供了一系列操作码来完成压入值到这个栈中,这个过程的术语叫加载(load)。同时,CIL也定义了一系列操作码来将栈顶的值移到内存中(例如局部变量),这个过程的术语叫存储(store)。
CIL不允许直接访问一个数据,包括局部变量、方法中传入的变量或者类型的字段数据。为了实现访问,必须显示地加载数据到栈中,并在使用时弹出。请留心这一点,因为这能够解释为什么CIL代码看起来有些冗余。
下面通过一段简单的没有参数和返回值的函数PrintMessage(),来理解CIL是如何应用栈这个模型的。在实现这个方法时,我们只将一个局部的字符串变量输出到标准的输出流。
public void PrintMessage()
{
string myMessage = "Hello";
Console.WriteLine(myMessage);
}