Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is object initialization preferred in the constructor? [duplicate]

Tags:

java

c#

Possible Duplicate:
C# member variable initialization; best practice?
Why should member variables be initialized in constructors?
Should I initialize variable within constructor or outside constructor

In Java/C# usually we see

public class MyClass {
    private MyObject myObject;

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

instead of

public class MyClass {
    private MyObject myObject = new MyObject();

    public MyClass(){

    }
}

What is the reason if any?

like image 825
Kenoyer130 Avatar asked Sep 12 '26 07:09

Kenoyer130


2 Answers

There is no difference, it's just a style choice.

In your example, if you choose the second approach you don't have to provide a constructor, which saves you a few lines of code.

like image 53
Keppil Avatar answered Sep 13 '26 19:09

Keppil


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.

  1. All initializers outside of a constructor are run first
  2. All base class constructors are called
  3. 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.

like image 28
vane Avatar answered Sep 13 '26 20:09

vane