我正在尝试弄清楚如何在C#中重现ref
修饰符的行为。
我有两种方法:
static void Foo(ref int x)
{
x = 25;
}
unsafe static void Foo(int* x)
{
*x = 25;
}
即使生成的这两种方法的IL代码相同,签名也不同:
Foo(ref int)
的代码:
.method private hidebysig static void Foo(int32& x) cil managed
{
// Code size 6 (0x6)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldc.i4.s 25
IL_0004: stind.i4
IL_0005: ret
} // end of method Program::Foo
Foo(int*)
.method private hidebysig static void Foo(int32* x) cil managed
{
// Code size 6 (0x6)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldc.i4.s 25
IL_0004: stind.i4
IL_0005: ret
} // end of method Program::Foo
所以我的问题是,为什么签名是不同的,而生成的代码是相同的?使用指针不能执行相同的工作吗?
注意:我编译了此代码Visual Studio 2015 Preview
,Debug Mode
。
答案 0 :(得分:4)
这两种方法实现IL的原因是stind.i4
opcode:
在提供的地址存储int32值(类型为native int,*或&)。
这意味着OpCode适用于指针和引用,因为它们实际上只是存储位置的地址。由于正在完成的工作与传入的类型不同,但应用相同的OpCode,因此方法体最终是相同的。
但这并不意味着它们是可互换的方法。他们需要以不同的方式打电话,这就是签名不同的原因。此外,这只是中间语言 - 它们很可能被JIT编译为机器代码。
答案 1 :(得分:1)
请记住,IL不是编译的最终结果,它是一种可移植的中间格式,可以提供给最终的编译器阶段。
IL指令根据操作数堆栈顶部的项目类型更改行为。 JIT编译器执行类型分析并确定stind
是否正在使用指针或引用,就像它确定add
是在处理整数还是浮点或指针一样。