Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing Class Fields at the Field Definition or in Class Constructor

I have a class with a field that needs to be initialized when the object is initialized, such as a list that needs to be created before objects can be added/removed from it.

public class MyClass1
{
    private List<MyOtherClass> _otherClassList;

    public MyClass1()
    {
        this._otherClasslist = new List<MyOtherClass>();
    }
}


public class MyClass2
{
    private List<MyOtherClass> = new List<MyOtherClass>();

    public MyClass2()
    {
    }
}

What is the difference between these two classes, and why would you choose one method over the other?

I usually set the field in the constructor, as in MyClass1, because I find it easier to be able to look in one place to see all the stuff that happens when the object is being instantiated, but is there any case where it is better to initialize a field directly like in MyClass2?

like image 239
Eric Anastas Avatar asked Jul 21 '09 03:07

Eric Anastas


People also ask

Where do you initialize class variables?

To initialize a class member variable, put the initialization code in a static initialization block, as the following section shows. To initialize an instance member variable, put the initialization code in a constructor.

How do you initialize a class constructor?

There are two ways to initialize a class object: Using a parenthesized expression list. The compiler calls the constructor of the class using this list as the constructor's argument list. Using a single initialization value and the = operator.

How can we initialize fields and methods using constructor?

Normally, you would put code to initialize an instance variable in a constructor. There are two alternatives to using a constructor to initialize instance variables: initializer blocks and final methods. The Java compiler copies initializer blocks into every constructor.

What happens when you don't initialize the fields in the constructor of a Java class?

A constructor is typically used to initialize instance variables representing the main properties of the created object. If we don't supply a constructor explicitly, the compiler will create a default constructor which has no arguments and just allocates memory for the object.


1 Answers

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.

like image 137
Chansik Im Avatar answered Oct 23 '22 02:10

Chansik Im