C#IL - 调用构造函数

Puc*_*acz 4 .net c# cil

我正在学习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)

现在,如何区分哪一个调用,在标签级别我们无法区分它.

The*_*aot 5

我去做实验了...

我使用了以下代码:

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 中尝试了与上面类似的代码,并且两者的调用看起来都很相似。


有关如何以二进制方式完成注释的详细信息......老实说我不知道​​。


Ben*_*igt 5

实际代码标识要由a调用的构造函数.MethodToken 这些构造函数对于每个重载都是唯一的.

您的反汇编程序具有不适当的令牌到字符串转换,它只提供名称,该名称不是唯一的,并且无法组装.相反,ildasm将令牌转换为完整签名,该签名能够往返于工作程序集(使用ilasm).