//示例一:输出整数的立方值。
private void PrintCube( int i )
{
int cube = i * i * i;
Console.WriteLine( cube );
}
//方法签名。
/**//// hidebysig:MethodAttributes 枚举值之一,指示此方法按名称和签名隐藏,否则只
/// 按名称隐藏。
/// cil managed:未查到具体资料,应是“受中间语言管理”之意。
.method private hidebysig instance void
PrintCube(int32 i) cil managed
{
// 代码大小 15 (0xf)
.maxstack 2
/**//**//**//// 在 .locals 部分声明所有的局部变量。
.locals init ([0] int32 cube) /**//**//**//// 第一个名局部变量,int 型,名为 cube。索
/// 引从 0 开始。
IL_0000: nop /**//**//**//// no operation.
IL_0001: ldarg.1 /**//**//**//// load argument 第一个方法参数入栈,比如“3”。索引号
/// 从 1 开始,而不是从 0 开始。
IL_0002: ldarg.1 /**//**//**//// 再次向堆栈压入第一个方法参数,又一个“3”。
IL_0003: mul /**//**//**//// multiply 计算堆栈最顶上两个数的乘积 3×3,并把结果入栈,
/// 即堆栈最顶部是 9 了。
IL_0004: ldarg.1 /**//**//**//// 再次压入第一个方法参数“3”。
IL_0005: mul /**//**//**//// 堆栈最顶上是“3”,第二是“9”,计算 3×9,此时 27 入栈。
IL_0006: stloc.0 /**//**//**//// pop value from stack to local variable 堆栈最顶上的
/// 值“27”出栈,并被赋给索引位置“0”处的局部变量 cube,
/// 即内存中变量 cube 的值为“27”。
IL_0007: ldloc.0 /**//**//**//// 局部变量 cube 的值“27”入栈。
IL_0008: call void [mscorlib]System.Console::WriteLine(int32)
/**//**//**//// 控制台输出堆栈最顶上的 32 位整数“27”。
IL_000d: nop /**//**//**//// no operation.
IL_000e: ret /**//**//**//// return from method.
} // end of method Program::PrintCube
//示例二:把字符串拆分成字符,并按顺序每行输出一个字符
public void SeparateString( string source )
{
if( source == null )
return;
int count = source.Length;
char c;
for( int i = 0; i < count; i++ )
{
c = source[ i ];
Console.WriteLine( c );
}
}
.method public hidebysig instance void
SeparateString(string source) cil managed
{
// 代码大小 55 (0x37)
.maxstack 2
.locals init ([0] int32 count,
[1] char c,
[2] int32 i,
[3] bool CS$4$0000) /**//**//**//// 索引为“3”的这个布尔型局部变量在 C# 代
/// 码中并未显式声明,是编译器编译时添加的,
/// 用于保存执行过程中布尔运算的结果,比如比
/// 较 source 是否为空时,以及比较 i<count 时。
IL_0000: nop
IL_0001: ldarg.1 /**//**//**//// 方法参数 source 的值入栈。
IL_0002: ldnull /**//**//**//// “空引用”null入栈。
IL_0003: ceq /**//**//**//// compare equal 比较栈顶的 null 和第二项的 source 是否相等,并
/// 把结果 0(false,source 不为空)或 1(true,source 为空)入栈。
IL_0005: ldc.i4.0 /**//**//**//// 32 位整型数“0”入栈。
IL_0006: ceq /**//**//**//// 比较栈顶的“0”和堆栈的第二项,第二项可能是“0”,也可能
/// 是“1”。比较的结果“1”或“0”入栈。
IL_0008: stloc.3 /**//**//**//// 栈顶的“1”或“0”出栈,被保存到索引为“3”的局部变量中。
IL_0009: ldloc.3 /**//**//**//// 执行后,栈顶为“1”(source 不为空)或“0”(source 为空)。
IL_000a: brtrue.s IL_000e /**//**//**//// branch on non-false or non-null 判断栈顶是否
/// 为“1”,如果是,跳转到第“IL_000e”行;否则
/// 继续往下执行。
IL_000c: br.s IL_0036 /**//**//**//// unconditional branch 当栈顶为“0”时,才会
/// 执行到这一行,这一行的执行结果是程序无条件
/// 跳转到第“IL_0036”行。
IL_000e: ldarg.1
IL_000f: callvirt instance int32 [mscorlib]System.String::get_Length()
/**//**//**//// 对堆栈最顶上的字符串调用其获取长度的实例方法,长度值被入栈。
/// “get_Length()”实际是字符串 Length 属性的“get”部分。
IL_0014: stloc.0 /**//**//**//// 局部变量 count 被赋值为字符串长度。
IL_0015: ldc.i4.0
IL_0016: stloc.2 /**//**//**//// 局部变量 i 被赋值为 0。
IL_0017: br.s IL_002e /**//**//**//// 无条件跳转到第“IL_002e”行。
IL_0019: nop
IL_001a: ldarg.1
IL_001b: ldloc.2
IL_001c: callvirt instance char [mscorlib]System.String::get_Chars(int32)
/**//**//**//// source 中索引为 i 处的 char 值入栈。
IL_0021: stloc.1
IL_0022: ldloc.1
IL_0023: call void [mscorlib]System.Console::WriteLine(char) /**//**//**//// char 值被输
/// 出到控制台。
IL_0028: nop
IL_0029: nop
IL_002a: ldloc.2 /**//**//**//// i 值入栈。
IL_002b: ldc.i4.1 /**//**//**//// 32 位整数 1 入栈。
IL_002c: add /**//**//**//// i+1 的结果入栈。
IL_002d: stloc.2 /**//**//**//// i=i+1。
IL_002e: ldloc.2 /**//**//**//// i 值入栈。
IL_002f: ldloc.0 /**//**//**//// count 值入栈。
IL_0030: clt /**//**//**//// compare less than 比较 i<count 是否为真,比较结果入栈。
IL_0032: stloc.3
IL_0033: ldloc.3
IL_0034: brtrue.s IL_0019 /**//**//**//// 如果 i<count 则跳转到第“IL_0019”行。
IL_0036: ret
} // end of method Program::SeparateString
总结分析:
ldstr: 将对字符串的对象引用推送到堆栈上
ldloc: 将变量的对象引用推送到堆栈上
idc.i4 idc.i8: 将4个字节的整数送到堆栈上,将超过32位的常数送到堆栈上
stloc index: 从堆栈中弹出值并将其放到局部变量index中,index 从0向上编号
newobj:初始化,调用构造函数,分配内存
call,callvirt: call 根据引用类型的静态类型来调度方法,callvirt根据引用类型的动态类型来调度方法
.ctor:构造函数,在类被实例化时,它会被自动调用。
Example 1
class Program
{
static void Main(string[] args)
{
String s = "a";
s = "abcd";
}
}
IL_0006: stloc.0 使用stloc指令从线程堆栈顶弹出先前压入的对象引用,将其传给局部变量s(其索引号为0)。
IL_0007: ldstr "abcd" 使用ldstr指令为字串对象“abcd”分配内存,并将此对象引用压入到线程堆栈中
IL_000c: stloc.0 使用stloc指令从线程堆栈顶弹出先前压入的对象引用,将其传给局部变量s(其索引号为0)。
s1+="cd";
(2)String s1="ab"+"cd";
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldstr "cd"
IL_000d: call string [mscorlib]System.String::Concat(string, string)
IL_0012: stloc.0
IL_0006: stloc.0
可以很清楚地看到,第(1)段代码将导致String类的Concat()方法被调用(实现字串加法运算)。对于第(2)段代码,由于C#编译器聪明地在编译时直接将两个字串合并为一个字串字面量,所以程序运行时CLR只调用一次ldstr指令就完成了所有工作,其执行速度谁快就不言而喻了!