1

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.

Sam
  • 2,166
  • 2
  • 20
  • 28
  • 2
    You can only chain once, and you can't chain from a parent to a child. – Oded Jul 27 '12 at 18:14
  • 1
    You want to call multiple constructors of the same class during class constructions? I don't think you even **can** do that. If you explain why you want to do this I am sure we can help you think of a different solution. – Anders Arpi Jul 27 '12 at 18:14
  • @Oded you're wrong, there **can** be more than one chained call (e.g `Child(): this(1)` and `Child(int val): base(val)` will effectively lead to following call order: `Parent(int), Child(int), Child()`. – Sergei Rogovtcev Jul 27 '12 at 18:17
  • @Sam Why would you want to do that? – Sergei Rogovtcev Jul 27 '12 at 18:17
  • @SergRogovtsev - I meant on one constructor. You can't do `Child(i) : base(i), this()` – Oded Jul 27 '12 at 18:18
  • @Oded that's why they're called *chained* – Sergei Rogovtcev Jul 27 '12 at 18:18
  • @SergRogovtsev - Yes, derived from daisy chains. I believe you understood my point and are simply nit picking. – Oded Jul 27 '12 at 18:22
  • @SergRogovtsev this is effectively what we want to do `Child(i) : base(i), this()`. We are just looking for a more elegant way to stay dry than adding a third function. – Sam Jul 27 '12 at 18:31
  • @Sam I understand *what* you want (and you can't do that), but I've asked *why* you want this (because there could be another solution). – Sergei Rogovtcev Jul 27 '12 at 18:33
  • @SergRogovtsev Basically, we have logic in each of the constructors and we want to execute all of them without have to repeat the code or add in extra methods. – Sam Jul 27 '12 at 18:38
  • Sounds like you are doing too much in your constructors. Consider a redesign - perhaps a shift to factories or builders. – Oded Jul 27 '12 at 18:42
  • @Oded That is one other option we discussed for building these objects. – Sam Jul 27 '12 at 19:03

5 Answers5

2

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

Sergei Rogovtcev
  • 5,804
  • 2
  • 22
  • 35
1

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");
    }
}
Joshua Honig
  • 12,925
  • 8
  • 53
  • 75
0

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.

phadaphunk
  • 12,785
  • 15
  • 73
  • 107
0

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.");
    }
}
Dan J
  • 16,319
  • 7
  • 50
  • 82
0

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)");
    }
}
Ben Lesh
  • 107,825
  • 47
  • 247
  • 232
  • Hopefully one of those helps you. I'm bookmarking this one because I'm really curious to see what you come up with. It's a strange problem to have, to be sure. – Ben Lesh Jul 27 '12 at 18:42
  • In the last example, I think the static variable won't get set before the Child parameterless constructor is called. Did you test it out? – Sam Jul 27 '12 at 19:06
  • Haha... you're right. Either way, I don't think you're ever going to get the order you want with any sort of ctor overload, because it's never going to execute the child ctor first. The parent ctor will always fire first. – Ben Lesh Jul 27 '12 at 19:56
  • Mostly I just wanted to take a crack at this one because it's kind of a fun question. – Ben Lesh Jul 27 '12 at 19:56