proper constructor chaining direction

I was looking at some code at my work and with several overloaded constructors having the same code in each one, I thought, beautiful, perfect place to use constructor chaining. Except I'm not sure which direction is the proper way to go

What I mean is, in the constructor, do you go from the general to the specific, using nulls for the missing parameters, or do you go from specific to general and then in the body of the constructor set the missing properties

Where things get interesting is when you want to call the base constructor, should it go in one place If you're using constructor chaining, then you can do this, but where does it go, at the top or the bottom of the chain

Here is a sample class that illustrates what I mean.

namespace ConstructorChaining

{

class Base

{

public StringBuilder orderOfExecution = new StringBuilder();

public Base()

{

orderOfExecution.Append("Base()\n");

}

public Base(String OrderOfExecution)

{

orderOfExecution.Append("Base(String " + OrderOfExecution + ")\n");

}

}

class ConstructorChaining : Base

{

public ConstructorChaining()

: this(null) //calling the more specialized constructor passing null to the more specific constructor

{

orderOfExecution.Append("GeneralToSpecific()\n");

}

public ConstructorChaining(String NewOrderOfConstruction)

{

orderOfExecution.Append("GeneralToSpecific(String " + (NewOrderOfConstruction == null "NULL" : NewOrderOfConstruction) + ")\n");

}

}

class SpecificToGeneral : Base

{

public SpecificToGeneral()

{

orderOfExecution.Append("SpecificToGeneral()\n");

}

public SpecificToGeneral(String NewOrderOfConstruction)

: this() //call the general case of the constructor

{

orderOfExecution.Append("SpecificToGeneral(String " + (NewOrderOfConstruction == null "NULL" : NewOrderOfConstruction) + ")\n");

}

}

}

Code to run it is here

namespace ConstructorChaining

{

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

Console.WriteLine("General To Specific");

ConstructorChaining generalToSpecific1 = new ConstructorChaining();

Console.WriteLine(generalToSpecific1.orderOfExecution.ToString());

ConstructorChaining generalToSpecific2 = new ConstructorChaining("InstantiatingVariable");

Console.WriteLine(generalToSpecific2.orderOfExecution.ToString());

Console.WriteLine("Specific To General");

SpecificToGeneral specificToGeneral1 = new SpecificToGeneral();

Console.WriteLine(specificToGeneral1.orderOfExecution);

SpecificToGeneral specificToGeneral2 = new SpecificToGeneral("InstantiatingVariable");

Console.WriteLine(specificToGeneral2.orderOfExecution);

}

}

}

And the sample output is

General To Specific

Base()

GeneralToSpecific(String NULL)

GeneralToSpecific()

Base()

GeneralToSpecific(String InstantiatingVariable)

Specific To General

Base()

SpecificToGeneral()

Base()

SpecificToGeneral()

SpecificToGeneral(String InstantiatingVariable)



Answer this question

proper constructor chaining direction

  • dlw10023

    Flip wrote:

    re cumulative constructors

    That's a good way to put it, is that indeed the technical term

    I've never heard the term "cumulative constructors" anywhere; I just used that to describe the multiple constructor case and how I implement it. Feel free to use the term :-).
    Flip wrote:

    re your Person example

    That's a good one, I can see now what you mean, so then you are not pushing a null parameter forward then. Instead you're going backwards to the more specific constructor/method call and then inside that constructor setting the properties that are specialized to that constructor's parameter list. Ok, I can see that logic and it makes sense.

    It follows the same logic as not assigning default values to instance members (the DoNotInitializeUnnecessarily rule). No logic errors will come from using "this(null)"; it's just redundant.



  • Montse

    re not sure you follow

    I'm trying to figure out which way do people use the constructor chaining.

    re don't overload constructor

    hhhmmmm I don't quite agree with that. The constructor is overloaded with two signatures in my example, one for empty parameters and one for a String parameter. Did you mean overriding The constructor of the derived class does not override the base class' constructor, they are still called when/if appropriate.

    re use whatever constructor applies

    I guess I'm asking, when you want to have one constructor call another (code reuse, maintenance, etc), which direction do you go, towards the more specific (applying nulls for the missing parameters) or to the more general (with specific lines of code in the constructor setting the properties, variables not set in the more general cases).

    As an example, in the code I have here at work, the empty constructor initializes a db proxy object. In all the other eight constructors, they each make that exact same call, so the same code is duplicated unnecessarily IMHO. What I think should be done, is have that db proxy object initialized in one of the constructor overloaded methods (either the empty one, or the most specific constructor, the one taking the most parameters). I hope that helps to clear things up a bit

    Thanks.


  • haba

    By not overloading, I meant you don't overload a base class's constructor.

    For me, I go in the most specific direction.

    I generally have a set of cumulative constructors, I then chain to the most specific constructor "below" the current one.

    For example:

    class Person
    {
    int age;
    String name:
    public Person(String name)
    {
    this.name = name;
    }
    public Person(String name, int age)
    : this(name)
    {
    this.age = age;
    }
    }

  • rodniko

    re don't overload base constructor

    Ah, ok, I see what you mean now.

    re cumulative constructors

    That's a good way to put it, is that indeed the technical term

    re your Person example

    That's a good one, I can see now what you mean, so then you are not pushing a null parameter forward then. Instead you're going backwards to the more specific constructor/method call and then inside that constructor setting the properties that are specialized to that constructor's parameter list. Ok, I can see that logic and it makes sense.

    Thank you very much for your time and explanation.


  • Guostong

    I'm not sure I follow your question. There's only one base so there really isn't a "chain"; and you don't overload a constructor.

    If the base's default constructor (parameter-less, if it exists) isn't applicable for the constructor of a derived class you should use whatever constructor applies in those circumstances. If a derived constructor provides no details that could apply, I would just use the default constructor. In your example using base(null), you're basically wasting cycles...

  • proper constructor chaining direction