13

Possible Duplicate:
Best Practice: Initialize class fields in constructor or at declaration?

Most of the time, I see the way of initializing a variable like this

public class Test
{
    private int myIntToInitalize;

    public Test()
    {
        myIntToInitalize = 10;
    }
}

From my perspective, this is the most general way of initializing a variable. Most of the code in books, blogs and also internal implementations of .NET are equivalent to my example.

Recently I saw people doing the initialization directly, so without setting the value in the constructor.

public class Test
{
    private int myIntToInitalize = 10;
}

In point of view, there is not difference whether initialize and declare a variable or initialize the variable in the constructor.

Apart from the best practices and the length of code lines, where are the benefits of initialize a variable directly and are there subtle differences?

Community
  • 1
  • 1
System.Data
  • 3,878
  • 7
  • 32
  • 40
  • 1
    Possible duplicate, http://stackoverflow.com/questions/24551/best-practice-initialize-class-fields-in-constructor-or-at-declaration and http://stackoverflow.com/questions/298183/c-sharp-member-variable-initialization-best-practice – Cyral Dec 29 '12 at 16:40
  • http://stackoverflow.com/a/14083981/922198 – Parimal Raj Dec 29 '12 at 17:14
  • I think its totally redundant to use constructor for this. Why complicate things and write more redundant code? I usually initialize in constructor only when this cannot be done directly, such as when you must pass some parameters to the constructor your variable initialization depends on. Otherwise: private int myIntToInitalize = 10; dont overcomplicate things keep them as simple as possible. Less code - is better !!! – monstro May 08 '18 at 15:33

6 Answers6

25

There's one potentially significant difference in some cases.

Instance initializers are executed before the base class constructor is executed. So if the base class constructor invokes any virtual methods which are overridden in the derived class, that method will see the difference. Usually this shouldn't be a noticeable difference, however - as invoking virtual methods in a constructor is almost always a bad idea.

In terms of clarity, if you initialize the variable at the point of declaration, it makes it very clear that the value doesn't depend on any constructor parameters. On the other hand, keeping all the initialization together helps readability too, IMO. I would try to make sure that wherever possible, if you have multiple constructors they all delegate to one "master" constructor which does all the "real" initialization - which means you'll only put those assignments in one place either way.

Sample code to demonstrate the difference:

using System;

class Base
{
    public Base()
    {
        Console.WriteLine(ToString());
    }
}

class Derived : Base
{
    private int x = 5;
    private int y;

    public Derived()
    {
        y = 5;
    }

    public override string ToString()
    {
        return string.Format("x={0}, y={1}", x, y);
    }
}

class Test
{
    static void Main()
    {
        // Prints x=5, y=0
        new Derived();
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
5

I'm not aware of any subtle differences. I usually like to put all initialization in the constructor, because I think it makes the code more readable. But that's more of a style choice and personal preference. I haven't heard of a technical reason to justify it one way or the other. I doubt that there's any performance impact.

Constants that are static and final are a different matter. I initialize those in-line.

duffymo
  • 305,152
  • 44
  • 369
  • 561
4

When an instance is constructed any variables that are initialized at declaration will be initialized before the constructor is run. If you are not accessing these variables or using their values in the constructor itself, then there is no functional difference between the two methods.

Jeff French
  • 1,029
  • 8
  • 22
  • 4
    They're even run before the base class constructors run. – CodesInChaos Dec 29 '12 at 16:43
  • This becomes more important when you're dealing with virtual methods. It isn't a good practice to call virtual methods from constructors, but if you ever call aVirtualMethod from Base constructor, and a class Derived overrides it, you'll find that any variable initializers will be 'executed' before aVirtualMethod is executed, but the Derived constructor wouldn't be executed yet. Additional info: http://blogs.msdn.com/b/ericlippert/archive/2008/02/15/why-do-initializers-run-in-the-opposite-order-as-constructors-part-one.aspx http://www.yoda.arachsys.com/csharp/constructors.html – Daniel Castro Dec 29 '12 at 16:52
3

lets say we compile the following code, under release & optimized builds

namespace ConsoleApplication4
{

    public class Test1
    {
        private int myIntToInitalize;

        public Test1()
        {
            myIntToInitalize = 10;
        }
    }

    public class Test2
    {
        private int myIntToInitalize = 10;
    }


    static class Program
    {

        private static void Main()
        {
        }


    }

}

The IL Instruction for Class Test1

.class public auto ansi beforefieldinit Test1
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: ldarg.0 
        L_0007: ldc.i4.s 10
        L_0009: stfld int32 ConsoleApplication4.Test1::myIntToInitalize
        L_000e: ret 
    }


    .field private int32 myIntToInitalize

}

The IL Instruction for Class Test2

.class public auto ansi beforefieldinit Test2
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: ldc.i4.s 10
        L_0003: stfld int32 ConsoleApplication4.Test2::myIntToInitalize
        L_0008: ldarg.0 
        L_0009: call instance void [mscorlib]System.Object::.ctor()
        L_000e: ret 
    }


    .field private int32 myIntToInitalize

}

is is very obvious that both the classes have same number of IL instruction, the only diff is,

variable is initialized before calling the ::ctor() in Class Test1; and variable is initialized after calling the ::ctor() in Class Test2;

NOTE : Performance wise both the Class will perform same, as they have same numbers & type of IL instruction, just that order of execution of IL Instruction is different

Parimal Raj
  • 20,189
  • 9
  • 73
  • 110
2

For your simple example, it is simply a matter of style.

There are subtle differences when inheritance is involved. For instance field initializers, the order of execution is derived class field initializers, base class field initializers, base class constructor, derived class constructor.

Take this sample:

public class Program
{
    public static void Main(string[] args)
    {
        new Derived();
    }
 }

 public class Base 
 {
     private int x = BaseInitializer();

     public Base()
     {
          Console.WriteLine("Base ctor");
     }

     private static int BaseInitializer()
     {
         Console.WriteLine("BaseInitializer");
         return 0;
     }
 }

 public class Derived : Base
 {
     private int x = DerivedInitializer();

     public Derived() : base()
     {
         Console.WriteLine("Derived ctor");
     }

     private static int DerivedInitializer()
     {
         Console.WriteLine("DerivedInitializer");
         return 0;
     }
 }

It prints:

  • DerivedInitializer
  • BaseInitializer
  • Base ctor
  • Derived ctor
Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
0
public class Test
{
    private int myIntToInitalize = 10;
    public Test()
    {

    }

    public Test(string x)
    {
    }
}

public class Test2
{
    private int myIntToInitalize;
    public Test2()
    {
        this.myIntToInitalize = 10;
    }

    public Test2(string x)
    {
    }
}

on class Test1 every object instance will have myIntToInitalize set to 10, but not on class Test2 when u call the constructor which required 1 parameter.

Hendrik T
  • 191
  • 7