Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# - What's the difference between these two ways of instancing a class property?

Tags:

c#

Basic C# question here.

What is the difference between creating an instance of a class property / field either as you declare it or in the constructor of the object in question. For example:

public class MyClass
{
    public MyObject = new MyObject();
}

vs

public class MyClass
{
    public MyObject;

    public MyCLass()
    {
        MyObject = new MyObject();
    }
}
like image 513
Sergio Avatar asked Jan 28 '11 10:01

Sergio


Video Answer


4 Answers

A field with an initializer is initialized before the base constructor is called, whereas if the initializer is in the body, that only gets executed after the base constructor is called.

This can be relevant if the base constructor calls a virtual method - but personally I'd try to avoid that situation.

Sample code:

public class Base
{
    public Base()
    {
        Dump();
    }

    public virtual void Dump() {}
}

public class Child : Base
{
    private string x = "Initialized at declaration";
    private string y;

    public Child()
    {
        y = "Initialized in constructor";
    }

    public override void Dump()
    {
        Console.WriteLine(x); // Prints "Initialized at declaration"
        Console.WriteLine(y); // Prints "" as y is still null
    }
}
like image 75
Jon Skeet Avatar answered Sep 28 '22 14:09

Jon Skeet


I compile these C# code:

public class MyClass1
{
    public MyObject MyObject = new MyObject();
}
public class MyClass2
{
    public MyObject MyObject;

    public MyClass2()
    {
        MyObject = new MyObject();
    }
}

I got IL assembly:

MyClass1:

.class public auto ansi beforefieldinit test.MyClass1
       extends [mscorlib]System.Object
{
  .field public class test.MyObject MyObject
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // code size:       19 (0x13)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  newobj     instance void test.MyObject::.ctor()
    IL_0006:  stfld      class test.MyObject test.MyClass1::MyObject
    IL_000b:  ldarg.0
    IL_000c:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0011:  nop
    IL_0012:  ret
  } // end of method MyClass1::.ctor

} // end of class test.MyClass1

MyClass2:

.class public auto ansi beforefieldinit test.MyClass2
       extends [mscorlib]System.Object
{
  .field public class test.MyObject MyObject
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // code size:       21 (0x15)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  nop
    IL_0008:  ldarg.0
    IL_0009:  newobj     instance void test.MyObject::.ctor()
    IL_000e:  stfld      class test.MyObject test.MyClass2::MyObject
    IL_0013:  nop
    IL_0014:  ret
  } // end of method MyClass2::.ctor
} // end of class test.MyClass2

It is prefectly clear that difference is only in the order of call to the base class constructor (System.Object::.ctor()), MyObject initializer (test.MyObject::.ctor()) and the class initializer (stfld class test.MyObject test.MyClass2::MyObject)

In the first case, MyClass1 initializes as follows:

  • MyObject initializer
  • class initializer (constructor assigment)
  • base class initializer (base class constructor)

But, MyClass2 initializes by that order:

  • base class initializer (base class constructor)
  • MyObject initializer
  • class initializer (constructor assigment)
like image 22
Artur Mustafin Avatar answered Oct 02 '22 14:10

Artur Mustafin


You can also use a static constructor that gets called before any other constructor where you can init static variables

public class Bus
{
   private static object m_object= null;

    // Static constructor:
    static Bus()
    {
        m_object = new object();

        System.Console.WriteLine("The static constructor invoked.");
    }

    public static void Drive()
    {
        System.Console.WriteLine("The Drive method invoked.");
    }
}

class TestBus
{
    static void Main()
    {
        Bus.Drive();
    }
}
like image 31
WraithNath Avatar answered Sep 30 '22 14:09

WraithNath


It's important to note that (in C#) the initializer assignment to the field will occur before the call to any base class constructor (as evidenced in this question about whether VB could be forced to do the same thing).

This means you can't use initializer syntax to reference a field of your base class (i.e. you can't directly translate this VB into C#):

Public Class Base
    Protected I As Int32 = 4
End Class

Public Class Class2
    Inherits Base

    Public J As Int32 = I * 10
End Class
like image 30
Damien_The_Unbeliever Avatar answered Oct 01 '22 14:10

Damien_The_Unbeliever