引言:
这篇我们讲解在.net IL中间语言中,经常见到的指令stfld。
该指令经常用在给一个对象的字段赋值。
MSDN解释如下:
Replaces the value stored in the field of an object reference or pointer with a new value.
翻译过来就是:用一个新值替换对象字段的值
命名空间是在 System.Reflection.Emit这个里面
程序集是mscorlib(mscorlib.dll中)
工作原理即堆栈转换行为如下:
按照先后顺序:
1.将一个对象引用或指针压入堆栈
2.将值被压入堆栈
3.该值和对象的引用/指针从堆栈中弹出,对象的字段更新为替换的值
C#程序:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Test test1=new Test();//new一个Test对象
test1.i = 12;//将Test对象的字段i赋值为12
}
/// <summary>
/// 测试类
/// </summary>
public class Test
{
public int i = 100;
}
}
}
IL 程序Main方法
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 16 (0x10)
.maxstack 2
.locals init ([0] class ConsoleApplication1.Program/Test test1)
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication1.Program/Test::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.s 12
IL_000a: stfld int32 ConsoleApplication1.Program/Test::i
IL_000f: ret
} // end of method Program::Main
我们来逐行分析下main方法的IL代码
.entrypoint //定义函数的入口点
// Code size 16 (0x10)//代码大小为16
.maxstack 2//栈的大小为2
.locals init ([0] class ConsoleApplication1.Program/Test test1)//定义一个变量为test1,存储在<本地变量列表>中第一个变量中
IL_0000: nop//空操作
IL_0001: newobj instance void ConsoleApplication1.Program/Test::.ctor()//new 一个Test对象,一个引用指向这个对象,引用存放在栈上,
对象存放在堆上面
IL_0006: stloc.0//将引用弹栈,存放到<本地变量列表>中的第一个变量中
IL_0007: ldloc.0//将<本地变量列表>中第一个变量的值压入堆栈
IL_0008: ldc.i4.s 12//将int 12压入堆栈
IL_000a: stfld int32 ConsoleApplication1.Program/Test::i//将堆栈的栈顶的值赋值给堆栈的第二个值,即test.i=12
IL_000f: ret//函数返回
在指令stfld 执行之前的内存图
堆栈中存放12,test1的地址,<本地变量列表>第一个变量中存放的是test1的地址,堆中存放的是test1指向的一个对象,其中test1.i=100
在指令stfld 执行之后的内存图
堆栈中的12,test1的地址弹出,<本地变量列表>第一个变量中存放的是test1的地址不变,堆中存放的是test1.i=12
本篇主要讲的就是对象的字段如何在内存中是如何赋值的,以及从每一行IL指令分析stfld 的执行过程。从底层分析对象的字段的赋值,可以更加清晰地看到赋值的过程。
下篇我会从.net底层剖析参数的传递,有兴趣的可以关注我哦!