我正在学习C#IL简单的例子而且无法理解.我有一个非常简单的程序:
void Main()
{
C c = new C(1);
}
class C
{
public C(){}
public C(int i){}
}
Run Code Online (Sandbox Code Playgroud)
有CIL:
IL_0001: ldc.i4.1
IL_0002: newobj UserQuery+C..ctor
IL_0007: stloc.0 // c
C..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: nop
IL_0007: nop
IL_0008: nop
IL_0009: ret
C..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: nop
IL_0007: nop
IL_0008: nop
IL_0009: ret
Run Code Online (Sandbox Code Playgroud)
我不明白,虚拟机将如何区分应该调用哪一个构造函数.有两个相同的标签,唯一的区别似乎是推动主要论证.调用构造函数时有更深层次的东西吗?也许编译器提供一些元数据来区分应该调用哪一个?
所以我们假设这个:
void Main()
{
C c = new C(1);
}
class C
{
public C(){}
public C(int i){ i += 1;}
}
IL_0001: ldc.i4.1
IL_0002: newobj UserQuery+C..ctor
IL_0007: stloc.0 // c
C..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: nop
IL_0007: nop
IL_0008: nop
IL_0009: ret
C..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.1
IL_0009: ldc.i4.1
IL_000A: add
IL_000B: starg.s 01
IL_000D: nop
IL_000E: ret
Run Code Online (Sandbox Code Playgroud)
现在,如何区分哪一个调用,在标签级别我们无法区分它.
我去做实验了...
我使用了以下代码:
class Program
{
static void Main()
{
CallConstructorA();
CallConstructorB();
}
static void CallConstructorA()
{
GC.KeepAlive(new C());
}
static void CallConstructorB()
{
GC.KeepAlive(new C(1));
}
}
class C
{
public C() { }
public C(int i)
{
GC.KeepAlive(i);
}
}
Run Code Online (Sandbox Code Playgroud)
以下是使用 Telerik JustDecompile 为 Program 类获得的 MSIL:
.class private auto ansi beforefieldinit Test.Program
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
}
.method private hidebysig static void CallConstructorA () cil managed
{
IL_0000: nop
IL_0001: newobj instance void Test.C::.ctor()
IL_0006: call void [mscorlib]System.GC::KeepAlive(object)
IL_000b: nop
IL_000c: ret
}
.method private hidebysig static void CallConstructorB () cil managed
{
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: newobj instance void Test.C::.ctor(int32)
IL_0007: call void [mscorlib]System.GC::KeepAlive(object)
IL_000c: nop
IL_000d: ret
}
.method private hidebysig static void Main () cil managed
{
.entrypoint
IL_0000: nop
IL_0001: call void Test.Program::CallConstructorA()
IL_0006: nop
IL_0007: call void Test.Program::CallConstructorB()
IL_000c: nop
IL_000d: ret
}
}
Run Code Online (Sandbox Code Playgroud)
所以你可以看到调用是不同的......
第一个说:
IL_0001: newobj instance void Test.C::.ctor()
Run Code Online (Sandbox Code Playgroud)
第二个说:
IL_0002: newobj instance void Test.C::.ctor(int32)
Run Code Online (Sandbox Code Playgroud)
所以,我猜是你的反编译器没有显示中间代码的所有细节。事实上,我确实在 LINQPad 中尝试了与上面类似的代码,并且两者的调用看起来都很相似。
有关如何以二进制方式完成注释的详细信息......老实说我不知道。
实际代码标识要由a调用的构造函数.MethodToken 这些构造函数对于每个重载都是唯一的.
您的反汇编程序具有不适当的令牌到字符串转换,它只提供名称,该名称不是唯一的,并且无法组装.相反,ildasm将令牌转换为完整签名,该签名能够往返于工作程序集(使用ilasm).