This boils down to coding preference as stated in one of the comments. If you compile the following code
public class TestInitialization
{
private object test1 = new object();
private object test2;
public TestInitialization()
{
this.test2 = new object();
}
}
When compiled, the actual code used is as follows
public class TestInitialization
{
private object test1;
private object test2;
public TestInitialization()
{
this.test1 = new object();
this.test2 = new object();
}
}
So they are exactly the same thing, use whichever you prefer.
EDIT:
Here is an example of a base class with an inherited class and the resultant compiled IL.
Base class
class basetest
{
private object test1 = new object();
private object test2;
public basetest()
{
this.test2 = new object();
}
}
Inherited class
class testclass : basetest
{
private object testclass1 = new object();
private object testclass2;
public testclass() : base()
{
this.testclass2 = new object();
}
}
Resulting IL Base class
.class private auto ansi beforefieldinit basetest
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: newobj instance void [mscorlib]System.Object::.ctor()
L_0006: stfld object logtest.basetest::test1
L_000b: ldarg.0
L_000c: call instance void [mscorlib]System.Object::.ctor()
L_0011: nop
L_0012: nop
L_0013: ldarg.0
L_0014: newobj instance void [mscorlib]System.Object::.ctor()
L_0019: stfld object logtest.basetest::test2
L_001e: nop
L_001f: ret
}
.field private object test1
.field private object test2
}
Inherited class IL
.class private auto ansi beforefieldinit testclass
extends logtest.basetest
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: newobj instance void [mscorlib]System.Object::.ctor()
L_0006: stfld object logtest.testclass::testclass1
L_000b: ldarg.0
L_000c: call instance void logtest.basetest::.ctor()
L_0011: nop
L_0012: nop
L_0013: ldarg.0
L_0014: newobj instance void [mscorlib]System.Object::.ctor()
L_0019: stfld object logtest.testclass::testclass2
L_001e: nop
L_001f: ret
}
.field private object testclass1
.field private object testclass2
}
I think there's a bit of confusing on my part. In this example the initializer outside of the constructor is initialized FIRST just before the base constructor is called. So no matter what, initializers outside of a constructor will be initialized first before the ones inside a constructor and for the most part this shouldn't matter. Technically they all get converted to be intialized inside a constructor and the following rules apply.
- All initializers outside of a constructor are run first
- All base class constructors are called
- All initializers inside constructor are run
Basically the compiler prepends all initializers outside the constructor to the constructor code and then runs as normal.
So this
public class test : basetest
{
private object test1 = new object();
private object test2;
public test() : base()
{
this.test2 = new object();
}
}
public class basetest
{
private object basetest1 = new object();
private object basetest2;
public basetest()
{
this.basetest2 = new object();
}
}
becomes
public class test : basetest
{
private object test1;
private object test2;
public test()
{
//prepend everything first
this.test1 = new object();
//call base
base(); //not legal but just an example
//everything else that was already here
this.test2 = new object();
}
}
public class basetest
{
private object basetest1;
private object basetest2;
public basetest()
{
//prepend initializers
this.basetest1 = new object();
//if there were more base classes, the constructors would be called here
//do everything else that was already here
this.basetest2 = new object();
}
}
Hopefully that makes more sense and clears some things up. I know I was having an issue understand what some people were meaning when they said it runs "first" or "outside" of the constructor; it does in fact ALL run INSIDE a constructor but the order of what is called is affected.