How does field initialization work in constructors?

Asked

Viewed 157 times

8

In the C# documentation it is written:

If a class does not have a constructor, a default constructor is Automatically generated and default values are used to initialize the Object Fields

That is, if a class does not have a constructor, a default constructor is automatically generated and default values are assigned to the class fields. But, if I declare a constructor without parameters (in which I believe it to be a default constructor), it seems that it still initializes the fields for its default value, example:

    public class SimpleClass
    {
        public int Number { get; private set; }

        public SimpleClass()
        {

        }

        public void Increment()
        {
            Number++;
        }

    }


    static void Main(string[] args)
    {
        SimpleClass sc = new SimpleClass();
        sc.Increment();
        Console.WriteLine(sc.Number); // Mostra: 1
        Console.ReadKey();
    }

But this is invalid:

    int i;
    i++;

Why?

  • 1

    What you say is invalid is actually valid. There’s some confusion there?

  • I think you confused builder with method. public SimpleClass() is your builder , public void Increment() is your method, in your Main you make an instance of your class and call your method and increment your variable this causes Number is equal to 1.

3 answers

8


Maybe the best way to look at it is to look at the code CIL:

.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 4:0:0:0
}
.assembly '510a4553-ce16-420a-a407-708c596fefd2'
{
  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module '510a4553-ce16-420a-a407-708c596fefd2.dll'
// MVID: {CA762240-7FEE-4C94-8DA0-A08E521CA6D0}
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x01140000


// =============== CLASS MEMBERS DECLARATION ===================

.class public auto ansi beforefieldinit Program
       extends [mscorlib]System.Object
{
  .method public hidebysig static void  Main(string[] args) cil managed
  {
    // 
    .maxstack  1
    .locals init (class SimpleClass V_0)
    IL_0000:  nop
    IL_0001:  newobj     instance void SimpleClass::.ctor()
    IL_0006:  stloc.0
    IL_0007:  ldloc.0
    IL_0008:  callvirt   instance void SimpleClass::Increment()
    IL_000d:  nop
    IL_000e:  ldloc.0
    IL_000f:  callvirt   instance int32 SimpleClass::get_Number()
    IL_0014:  call       void [mscorlib]System.Console::WriteLine(int32)
    IL_0019:  nop
    IL_001a:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    IL_001f:  pop
    IL_0020:  ret
  } // end of method Program::Main

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // 
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method Program::.ctor

} // end of class Program

.class public auto ansi beforefieldinit SimpleClass
       extends [mscorlib]System.Object
{
  .field private int32 '<Number>k__BackingField'
  .method public hidebysig specialname instance int32 
          get_Number() cil managed
  {
    // 
    .maxstack  1
    .locals init (int32 V_0)
    IL_0000:  ldarg.0
    IL_0001:  ldfld      int32 SimpleClass::'<Number>k__BackingField'
    IL_0006:  stloc.0
    IL_0007:  br.s       IL_0009

    IL_0009:  ldloc.0
    IL_000a:  ret
  } // end of method SimpleClass::get_Number

  .method private hidebysig specialname instance void 
          set_Number(int32 'value') cil managed
  {
    // 
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  ldarg.1
    IL_0002:  stfld      int32 SimpleClass::'<Number>k__BackingField'
    IL_0007:  br.s       IL_0009

    IL_0009:  ret
  } // end of method SimpleClass::set_Number

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // 
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  nop
    IL_0008:  ret
  } // end of method SimpleClass::.ctor

  .method public hidebysig instance void 
          Increment() cil managed
  {
    // 
    .maxstack  3
    .locals init (int32 V_0)
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  call       instance int32 SimpleClass::get_Number()
    IL_0007:  stloc.0
    IL_0008:  ldarg.0
    IL_0009:  ldloc.0
    IL_000a:  ldc.i4.1
    IL_000b:  add
    IL_000c:  call       instance void SimpleClass::set_Number(int32)
    IL_0011:  nop
    IL_0012:  ret
  } // end of method SimpleClass::Increment

  .property instance int32 Number()
  {
    .get instance int32 SimpleClass::get_Number()
    .set instance void SimpleClass::set_Number(int32)
  } // end of property SimpleClass::Number
} // end of class SimpleClass

Especially:

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // 
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method Program::.ctor

The compiler generated a method called .ctor. He is a instance method, non-static treated in a special way by CLR and he always calls the builder of the ascending class, in the case Object.

But if you have a static constructor, then it will be called .cctor and will still be static (and necessarily private:

  .method private hidebysig specialname rtspecialname static 
          void  .cctor() cil managed
  {
    // 
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method Program::.cctor

In a constructor created by the programmer would have other codes there, and could even assign values to class members. Regardless of this there is the initialization of the members occurring during the construction (performed by the independent CLR and before the constructor, as can be observed in another question on the subject.

Note that there is a constructor in both classes. In general a class that will only have static members can be declared static and avoid the existence of the instance builder.

6

Because your class also wins an implicit constructor, nicknamed ctor. It is created when there are no constructors defined by the programmer.

I don’t know if you ever had this idea of putting a breakpoint on SimpleClass sc = new SimpleClass(); and squeeze F11. The next line of execution will fall here:

public int Number { get; private set; }

That is, whether you have an empty constructor or not, the class needs to initialize the property one way or another.

At this startup, some values are set by default when the programmer does not inform them. Here you can see them all.

0

no c# todo has 2 types of data
types of references:referency type these types receive default values null,
types of val:value type ex:int,char,bool. these have a default value, preset, and the int is 0
in this case: int i; i++; gives a build error that a way of preventing the compiler, but in another case are already in run time and then properties receive all their default values, so no error,

another thing is that the int and whole value type are non nullable type or are never null.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.