继续学习IL代码,现在我们看下常用的属性器到底是怎么执行的:
C#代码如下:
using System;
namespace ConsoleApp1
{
public class MyClass
{
public MyClass(int v)
{
val = v;
}
private int val { get; set; }
public int GetVal()
{
return val++;
}
}
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass(12);
Console.WriteLine(myClass.GetVal());
}
}
}
.namespace ConsoleApp1 // .namespace:命名空间
{
.class public auto ansi beforefieldinit ConsoleApp1.MyClass //.class 类标识 auto 类的布局方式 ansi 指定类中的字符串必须转换成ANSI字符
extends [System.Runtime]System.Object //.NET Core中beforfieldinit特性时当有一个静态变量被使用时就初始化所有静态变量- //所有对象继承自基类object
{
// Fields
.field private int32 'k__BackingField' //.field声明字段
//字段自动生成的两个属性 .custom 自定义方法 .ctor()构造方法 .cctor静态构造方法
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [System.Diagnostics.Debug]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [System.Diagnostics.Debug]System.Diagnostics.DebuggerBrowsableState) = (
01 00 00 00 00 00 00 00
)
// Methods
.method public hidebysig specialname rtspecialname //.method 方法标识 hidebysig 隐藏签名 specialname 特定方法标识
instance void .ctor (
int32 v
) cil managed //cil managed 标识IL中实现的方法
{
// Method begins at RVA 0x2050
// Code size 17 (0x11)
.maxstack 8 //.maxstack标识JIT它需要保留该方法的最大堆栈大小--just In Time Complier 将中间语言编译成计算机可以理解的机器码
IL_0000: ldarg.0 //将参数0位加载到堆栈 this
IL_0001: call instance void [System.Runtime]System.Object::.ctor() //调用构造方法初始化类
IL_0006: nop //nothing to do
IL_0007: nop //nothing to do
IL_0008: ldarg.0 //将参数0位加载到堆栈 this
IL_0009: ldarg.1 //将参数1位加载到堆栈(1位为真正的参数)
IL_000a: call instance void ConsoleApp1.MyClass::set_val(int32) //执行类myclass中 val 属性器的set方法
IL_000f: nop //nothing to do
IL_0010: ret //从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
} // end of method MyClass::.ctor
.method private hidebysig specialname //.method 方法标识 hidebysig 隐藏签名 specialname 特定方法标识
instance int32 get_val () cil managed //cil managed 标识IL中实现的方法
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2062
// Code size 7 (0x7)
.maxstack 8 //.maxstack标识JIT它需要保留该方法的最大堆栈大小--just In Time Complier 将中间语言编译成计算机可以理解的机器码
IL_0000: ldarg.0 //将参数0位加载到堆栈 this
IL_0001: ldfld int32 ConsoleApp1.MyClass::'k__BackingField' /从堆栈0位读取值
IL_0006: ret //从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
} // end of method MyClass::get_val
.method private hidebysig specialname
instance void set_val (
int32 'value'
) cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x206a
// Code size 8 (0x8)
.maxstack 8 //.maxstack标识JIT它需要保留该方法的最大堆栈大小--just In Time Complier 将中间语言编译成计算机可以理解的机器码
IL_0000: ldarg.0 //将参数0位加载到堆栈 this
IL_0001: ldarg.1 //将参数1位加载到堆栈
IL_0002: stfld int32 ConsoleApp1.MyClass::'k__BackingField' //替换在对象引用或指针的字段中存储的值
IL_0007: ret //从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
} // end of method MyClass::set_val
.method public hidebysig
instance int32 GetVal () cil managed
{
// Method begins at RVA 0x2074
// Code size 24 (0x18)
.maxstack 2
.locals init (
[0] int32,
[1] int32
) //初始化局部变量
IL_0000: nop //nothing todo
IL_0001: ldarg.0 //将索引为 0 的参数加载到计算堆栈上
IL_0002: call instance int32 ConsoleApp1.MyClass::get_val() //调用get_val() 获取到val 的值
IL_0007: ldc.i4.1 //将整数值 1 作为 int32 推送到计算堆栈上
IL_0008: add //执行相加命令
IL_0009: stloc.0 //从计算堆栈的顶部弹出当前值并将其存储到索引 0 处的局部变量列表中
IL_000a: ldarg.0 // 将索引为 0 的参数加载到计算堆栈上
IL_000b: ldloc.0 //将索引 0 处的局部变量加载到计算堆栈上
IL_000c: call instance void ConsoleApp1.MyClass::set_val(int32) //调用set_val 设置val 值
IL_0011: nop //nothing todo
IL_0012: ldloc.0 //将索引 0 处的局部变量加载到计算堆栈上
IL_0013: stloc.1 //从计算堆栈的顶部弹出当前值并将其存储到索引 1 处的局部变量列表中
IL_0014: br.s IL_0016 //跳转IL_0016
IL_0016: ldloc.1 //将索引 1 处的局部变量加载到计算堆栈上
IL_0017: ret //返回
} // end of method MyClass::GetVal
// Properties
.property instance int32 val()
{
.get instance int32 ConsoleApp1.MyClass::get_val()
.set instance void ConsoleApp1.MyClass::set_val(int32)
}
} // end of class ConsoleApp1.MyClass
.class private auto ansi beforefieldinit ConsoleApp1.Program
extends [System.Runtime]System.Object
{
// Methods
.method private hidebysig static
void Main (
string[] args
) cil managed
{
// Method begins at RVA 0x2098
// Code size 22 (0x16)
.maxstack 1
.entrypoint
.locals init (
[0] class ConsoleApp1.MyClass myClass
) //局部变量 初始化
IL_0000: nop
IL_0001: ldc.i4.s 12 // ldc.i4.s 命令 将提供的 int8 值作为 int32 推送到计算堆栈上 --初始化
IL_0003: newobj instance void ConsoleApp1.MyClass::.ctor(int32) //调用构造方法初始化 newobj
IL_0008: stloc.0 //从计算堆栈的顶部弹出当前值并将其存储到索引 0 处的局部变量列表中
IL_0009: ldloc.0 //将索引 0 处的局部变量加载到计算堆栈上
IL_000a: callvirt instance int32 ConsoleApp1.MyClass::GetVal() //调用方法 getval() 计算
IL_000f: call void [System.Console]System.Console::WriteLine(int32) //调用输出方法
IL_0014: nop
IL_0015: ret //return
} // end of method Program::Main
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed //构造函数
{
// Method begins at RVA 0x20ba
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0 //this
IL_0001: call instance void [System.Runtime]System.Object::.ctor() //调用基类的构造函数
IL_0006: nop
IL_0007: ret
} // end of method Program::.ctor
} // end of class ConsoleApp1.Program
}
几乎每行每个关键字与功能都做了注解,不另外做解释。
每天学一点,总会有收获。