Sam
Sam

Reputation: 2201

C# Constructor Chaining

Given the two classes below, I would like to call the Child constructor with the int parameter, then the parent constructor with the int parameter and last the Child parameterless constructor.

Can this be done without the use of optional parameters?

public class Parent
{
    public Parent()
    {
        Console.WriteLine("Parent ctor()");
    }

    public Parent(int i)
    {
        Console.WriteLine("Parent ctor(int)");
    }
}

public class Child:Parent
{
    public Child()
    {
        Console.WriteLine("Child ctor()");
    }

    public Child(int i)
    {
        Console.WriteLine("Child ctor(int)");
    }
}

Here is the logic in .NET 4 we want to accomplish in .NET 2.0

public class Parent2
{
    public Parent2(int? i = null)
    {
        Console.WriteLine("Parent2 ctor()");

        if (i != null)
        {
            Console.WriteLine("Parent2 ctor(int)");

        }
    }
}

public class Child2 : Parent2
{
    public Child2(int? i = null)
        : base(i)
    {
        Console.WriteLine("Child2 ctor()");

        if (i != null)
        {
            Console.WriteLine("Child2 ctor(int)");
        }
    }
}

Here is the production code we were discussing

public class DataPoint<T>
{
    public DataPoint() { }

    public DataPoint(T xValue, int yValue)
    {
        XAxis = xValue;
        YAxis = yValue;
    }

    public T XAxis { get; set; }
    public int YAxis { get; set; }
}

public class DataPointCollection<T> : DataPoint<T>
{
    DataPointCollection()
    {
        Labels = new List<string>();
    }

    DataPointCollection(T xValue, int yValue)
        : base(xValue, yValue)
    { }

    public List<string> Labels { get; set; }
}

EDIT:

At this point the reason for the question is a "Code Golf" academic exercise to follow a DRY methodology in the least amount of code. The normal pattern is to use an internal private function in the class that has the common code to execute from each of the constructors.

EDIT 2

I added the example production code.

Upvotes: 1

Views: 522

Answers (5)

Ben Lesh
Ben Lesh

Reputation: 108501

There are a few choices, but none of them are perfect. In the end my main recommendation would be to upgrade to .NET 4.0 if you can (obviously).

Here's one option, use an object then cast as whatever you need to inside of there. This is obvious disadvantages since you're going to lose typing or break signatures but it might work for your situation, I don't know:

public class Parent3
{
    public Parent3(object i)
    {
        Console.WriteLine("Parent3 ctor()");

        if (i != null)
        {
            Console.WriteLine("Parent3 ctor(int)");
        }
    }
}

public class Child3 : Parent3
{
    public Child3(object i)
        : base(i)
    {
        Console.WriteLine("Child3 ctor()");

        if (i != null)
        {
            Console.WriteLine("Child3 ctor(int)");
        }
    }
}

Here's another option, use Init methods. They won't fire in the exact same order, however, but it might work for you.

    public class Parent
{
    public Parent()
    {
        Init();
    }

    protected void Init()
    {
        Console.WriteLine("Parent ctor()");
    }

    public Parent(int i)
    {
        Init(i);
    }

    protected void Init(int i)
    {
        Console.WriteLine("Parent ctor(int)");
    }
}

public class Child : Parent
{
    public Child()
    {
        Init();
    }

    protected void Init()
    {
        Console.WriteLine("Child ctor()");
    }

    public Child(int i)
    {
        Init(i);
        base.Init(i);
        Init();
    }


    protected void Init(int i)
    {
        Console.WriteLine("Child ctor(int)");
    }

}

Then here is a way you can do it that I really don't recommend, but I'll include it anyway:

    public class Parent
{
    public Parent()
    {
        Console.WriteLine("Parent ctor()");
    }

    public Parent(int i)
    {
        Console.WriteLine("Parent ctor(int)");
    }
}

public class Child : Parent
{
    private static int _i; //this is likely to blow up at some point.

    public Child() : base(_i)
    {
        Console.WriteLine("Child ctor()");
    }

    public Child(int i) : this()
    {
        _i = i;
        Console.WriteLine("Child ctor(int)");
    }
}

Upvotes: 0

Joshua Honig
Joshua Honig

Reputation: 13225

If you need a series of initialization methods, I recommend you define them as such -- as normal (not constructor) methods. You can set up the back-and-forth using an overridable protected methods, as the constructors can choose which initialization methods to call in any combination or order:

public class Parent {

    public Parent() { }

    public Parent(int i) {
        initWithArg(i);
        initNoArgs();
    }

    virtual protected void initWithArg(int i) {
        Console.WriteLine("Parent initWithArg(int)");
    }

    virtual protected void initNoArgs() {
        Console.WriteLine("Parent initNoArgs");
    }
}

public class Child : Parent {

    // Override the *parameterless* constructor
    public Child(int i) : base() {
        initWithArg(i);
        base.initWithArg(i);
        initNoArgs();
    }

    override protected void initWithArg(int i) {
        Console.WriteLine("Child initWithArg(int)");
    }

    override protected void initNoArgs() {
        Console.WriteLine("Child initNoArgs");
    }
}

Upvotes: 1

phadaphunk
phadaphunk

Reputation: 13313

The Inheritance only works as a one way.

Child ---> Parent

You probably have a structure error because (someone correct me if i'm wrong) there is no scenarios where you would have to call two constructors of the same class at the tame time.

Except for recursive constructors because it calls itself so it's not the same thing.

Upvotes: 0

Dan J
Dan J

Reputation: 16718

You can accomplish the first part of your question by defining the Child(int i) constructor like so:

public Child(int i) : base(i)
{
    Console.WriteLine("Child ctor(int)");
}

But, as mentioned, you can't subsequently call another of Child's constructors. If your actual goal (assuming this is not a purely academic question) is to ensure some standard behaviour contained in Child's default constructor is always executed, you may be better off encapsulating it in a method and calling it from each of Child's constructors:

public class Child:Parent
{
    public Child()
    {
        Console.WriteLine("Child ctor()");
        CommonChildConstructionBehaviour();
    }

    public Child(int i) : base(i)
    {
        Console.WriteLine("Child ctor(int)");
        CommonChildConstructionBehaviour();
    }

    private void CommonChildConstructionBehaviour()
    {
        Console.WriteLine("All child constructors must call me.");
    }
}

Upvotes: 0

Sergei Rogovtcev
Sergei Rogovtcev

Reputation: 5832

No, you can't do that, because you can't call Child constructor from Parent.

Upvotes: 2

Related Questions