Initialize Class Fields in Constructor or At Declaration

Initialize class fields in constructor or at declaration?

My rules:

  1. Don't initialize with the default values in declaration (null, false, 0, 0.0…).
  2. Prefer initialization in declaration if you don't have a constructor parameter that changes the value of the field.
  3. If the value of the field changes because of a constructor parameter put the initialization in the constructors.
  4. Be consistent in your practice (the most important rule).

Initialization of variables: Directly or in the constructor?

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

Initializing Fields Value in Constructor Versus in Fields Declaration

The advantage with an argumented constructors is that you can set the field values as per the inputs but you cant do the same with initialized fields.

So if you want to create different objects with different attribute values then go for constructors with arguements. And assign the values of instance variables in your constructor.

If you simply want all the instance variables to have some default value, then assign the values at declaration.

Initializing on declaration vs initializing in constructors

If the member can only be set via an accessor (a "setter" method), I prefer the first style. It provides a hint that the initialized value is the default upon construction.

If the member can be specified during construction, I generally pass the default value to an appropriate constructor from constructor with fewer parameters. For example,

final class Dude {

private final String name;

Dude() {
this("El Duderino");
}

Dude(String name) {
this.name = name;
}

}

Should I initialize variable within constructor or outside constructor

I find the second style (declaration + initialization in one go) superior. Reasons:

  • It makes it clear at a glance how the variable is initialized. Typically, when reading a program and coming across a variable, you'll first go to its declaration (often automatic in IDEs). With style 2, you see the default value right away. With style 1, you need to look at the constructor as well.
  • If you have more than one constructor, you don't have to repeat the initializations (and you cannot forget them).

Of course, if the initialization value is different in different constructors (or even calculated in the constructor), you must do it in the constructor.

Initializing Class Fields at the Field Definition or in Class Constructor

The ILs emitted by C# compiler (VS2008 sp1) will be almost equivalent for both cases (even in Debug and Release builds).

However, if you need to add parameterized constructors that take List<MyOtherClass> as an argument, it will be different (especially, when you will create a significantly large number of objects with such constructors).

See the following examples to see the differences (you can copy&past to VS and build it to see ILs with Reflector or ILDASM).

using System;
using System.Collections.Generic;

namespace Ctors
{
//Tested with VS2008 SP1
class A
{
//This will be executed before entering any constructor bodies...
private List<string> myList = new List<string>();

public A() { }

//This will create an unused temp List<string> object
//in both Debug and Release build
public A(List<string> list)
{
myList = list;
}
}

class B
{
private List<string> myList;

//ILs emitted by C# compiler are identicial to
//those of public A() in both Debug and Release build
public B()
{
myList = new List<string>();
}

//No garbage here
public B(List<string> list)
{
myList = list;
}
}

class C
{

private List<string> myList = null;
//In Release build, this is identical to B(),
//In Debug build, ILs to initialize myList to null is inserted.
//So more ILs than B() in Debug build.
public C()
{
myList = new List<string>();
}

//This is identical to B(List<string> list)
//in both Debug and Release build.
public C(List<string> list)
{
myList = list;
}
}

class D
{
//This will be executed before entering a try/catch block
//in the default constructor
private E myE = new E();
public D()
{
try
{ }
catch (NotImplementedException e)
{
//Cannot catch NotImplementedException thrown by E().
Console.WriteLine("Can I catch here???");
}
}
}

public class E
{
public E()
{
throw new NotImplementedException();
}
}

class Program
{
static void Main(string[] args)
{
//This will result in an unhandled exception.
//You may want to use try/catch block when constructing D objects.
D myD = new D();
}
}
}

Note: I did not change any optimization flag when switching to Release build.

Difference on initializing object inside class declaration v/s constructor

The difference here is really subtle, and can only easily be appreciated in IL:

class MyBuilder1
{
private MySynchronizer m_synchronizer = new MySynchronizer();

public MyBuilder1()
{

}
}

gives us the constructor:

.method public hidebysig specialname rtspecialname 
instance void .ctor () cil managed
{
// Method begins at RVA 0x2050
// Code size 18 (0x12)
.maxstack 8

IL_0000: ldarg.0
IL_0001: newobj instance void MySynchronizer::.ctor()
IL_0006: stfld class MySynchronizer MyBuilder1::m_synchronizer
IL_000b: ldarg.0
IL_000c: call instance void [mscorlib]System.Object::.ctor()
IL_0011: ret
} // end of method MyBuilder1::.ctor

where-as this:

class MyBuilder2
{
private MySynchronizer m_synchronizer;

public MyBuilder2()
{
m_synchronizer = new MySynchronizer();

}
}

gives us:

// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2063
// Code size 18 (0x12)
.maxstack 8

IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: newobj instance void MySynchronizer::.ctor()
IL_000c: stfld class MySynchronizer MyBuilder2::m_synchronizer
IL_0011: ret
} // end of method MyBuilder2::.ctor

The difference is simply one of ordering:

  • field initializers (MyBuilder1) happen before the base-type constructor call (object is the base here; call instance void [mscorlib]System.Object::.ctor() is the base-constructor call)
  • constructors happen after the base-type constructor call

In most cases, this won't matter. Unless your base-constructor invokes a virtual method that the derived type overrides: then whether or not the field has a value in the overridden method will be different between the two.



Related Topics



Leave a reply



Submit