C # IL - constructor call

I am studying a simple C # IL example and cannot understand anything. I have a very simple program:

void Main()
{
   C c = new C(1);
}
class C
{
   public C(){}
   public C(int i){}
}

have 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  

I do not understand how a virtual machine will distinguish what a call to one constructor should be. There are two identical labels, and the only difference seems to be that the main argument calls the argument. Is there anything deeper when calling the constructor? Maybe the compiler provides some metadata to distinguish which one should be named?

So let's say the following:

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   

Now, how to distinguish the called, at the label level, we can not distinguish it.

+4
source share
4 answers

I went to do an experiment ...

I used the following code:

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);
    }
}

- MSIL, Telerik JustDecompile Program:

.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
    }
}

, , ...

:

        IL_0001: newobj instance void Test.C::.ctor()

:

        IL_0002: newobj instance void Test.C::.ctor(int32)

, , , . LINQPad, .


, ... , .

+4

, MethodToken .

, , . constrast ildasm , ( ilasm).

+5

, . IL, -

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       9 (0x9)
  .maxstack  1
  .locals init ([0] class ConsoleTest.C c)
  IL_0000:  nop
  IL_0001:  ldc.i4.1
  IL_0002:  newobj     instance void ConsoleTest.C::.ctor(int32)
  IL_0007:  stloc.0
  IL_0008:  ret
} // end of method Program::Main

instance void ConsoleTest.C::.ctor(int32)

IL, , . Emit IL , , Emit API . , NewObj , NewObj opcode

ConstructorInfo

" newobj ctor"

" Emit newobj: ILGenerator.Emit(OpCode, ConstructorInfo)"

+2

IL

The easiest way to learn how to compile your example without passing to the 1constructor

this line will disappear: IL_0001: ldc.i4.1which means, I think, it will not pass an argument to the constructor.

do it again by passing 9 instead of 1, this IL_0001: ldc.i4.1will be replaced byIL_0001: ldc.i4.s 9

+1
source

Source: https://habr.com/ru/post/1568492/


All Articles