51

I have two classes, Foo and Bar, that have constructors like this:

class Foo
{
    Foo()
    {
      // do some stuff
    }

    Foo(int arg)
    {
      // do some other stuff
    }
}

class Bar : Foo
{
    Bar() : base()
    {
      // some third thing
    }
}

Now I want to introduce a constructor for Bar that takes an int, but I want the stuff that happens in Bar() to run as well as the stuff from Foo(int). Something like this:

Bar(int arg) : Bar(), base(arg)
{
  // some fourth thing
}

Is there any way to do this in C#? The best I have so far is putting the work done by Bar() into a function, that also gets called by Bar(int), but this is pretty inelegant.

Cœur
  • 37,241
  • 25
  • 195
  • 267
reilly
  • 513
  • 1
  • 4
  • 5

8 Answers8

32

I would re-chain constructors, so they are called like

Bar() : this(0) 
Bar(int) : Foo(int) initializes Bar
Foo(int) initializes Foo
Foo() : this(0) 

This is suitable, if parameterless constructors are assuming some kind of default value for int parameter of other constructor. If constructors are unrelated, you probably doing something wrong with your type, or maybe we need more information about what are you trying to achieve.

Ilya Ryzhenkov
  • 11,782
  • 1
  • 40
  • 50
24

No, this isn't possible. If you use Reflector to examine the IL that's generated for each constructor, you'll see why -- you'd end up calling both of the constructors for the base class. In theory, the compiler could construct hidden methods to accomplish what you want, but there really isn't any advantage over you doing the same thing explicitly.

Curt Hagenlocher
  • 20,680
  • 8
  • 60
  • 50
13

I would recommend changing your constructor chain to go from least specific to most specific.

class Foo
{
    Foo()
    {
      // do some stuff
    }

    Foo(int arg): this()
    {
      // do some other stuff
    }
}

class Bar : Foo
{
    Bar() : Bar(0)
    {
      // some third thing
    }

    Bar(int arg): base(arg)
    {
      // something
    }
}

Any creation of the Bar object will now call all 4 constructors. Constructor chaining should provide default values to more specific constructors, not the other way around. You should really look at what you are trying to accomplish and make sure what you are doing makes sense. Curt is right that there are technical reasons you can't do this, but there are also logical reasons why you shouldn't.

NerdFury
  • 18,876
  • 5
  • 38
  • 41
4

This is only thing I can think of...

 public class Foo
{
    public Foo()
    {
    }
    public Foo(int? arg): this()
    {
    }

}
public class Bar : Foo
{
    private int x;
    public Bar(): this(new int?()) // edited to fix type ambiguity
    {
        // stuff that only runs for paramerless ctor
    }
    public Bar(int? arg)
        : base(arg)
    {
        if (arg.HasValue)
        {
            // Do stuff for both parameterless and parameterized ctor
        }
        // Do other stuff for only parameterized ctor
    }
}
Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
  • You have +1 for the nullable idea, but it has some flow - if you add another ctor with one argument (of class type, not struct), it'll fail, as now this(null) will not know which one to choose. – Sunny Milenov Dec 02 '08 at 20:40
1

Can't you have the Bar constructor that takes an int invoke the parameterless constructor?

Jim Anderson
  • 3,602
  • 2
  • 24
  • 21
1

Can you put the stuff from Bar() in Bar(int) and call Bar(int) with Bar() with a default value? Then Bar(int) can call the base constructor.

class Bar : Foo
{
    Bar() : this(0)
    {
    }

    Bar(int arg) : base(arg)
    {
    }
}

That doesn't exactly answer your question, but depending on your scenario might be a workable solution.

g .
  • 8,110
  • 5
  • 38
  • 48
1

can you take the initialization code for Bar() and make it a method and call it from both constructors, and have the new constructor just call base(arg)?

CSharpAtl
  • 7,374
  • 8
  • 39
  • 53
0

You can use this code:

public Foo
{
    public Foo()
    {
        this.InitializeObject();
    }

    public Foo(int arg) : this()
    {
        // do something with Foo's arg
    }

    protected virtual void InitializeObject()
    {
        // initialize object Foo
    }
}

public Bar : Foo
{
    public Bar : base() { }

    public Bar(int arg) : base(arg)
    {
       // do something with Bar's arg
    }

    protected override void InitializeObject()
    {
       // initialize object Bar

       base.InitializeObject();
    }
}

Just override the InitializeObject() method just like in the code above, and put all your code that you want to put in parameter-less constructor there. And finally call base.InitializeObject() at the end of the code.

Hope this is useful.

ragingasiancoder
  • 616
  • 6
  • 17
Moch Yusup
  • 1,266
  • 14
  • 14
  • It's worth noting that while constructors can write `readonly` fields, an `InitializeObject` method will not be able to do so directly. To initialize such fields within an `InitializeObject` method, one must have the constructor pass them as `ref` or `out` parameters (I'd favor `ref`, since field values are defined to be blank when an object is constructed, and since I dislike `out` parameters on virtual methods since overrides in other languages may regard them as `ref` parameters). – supercat Apr 30 '13 at 16:03
  • You can do this for readonly fields : `private readonly string _ro1 = "read only 1"; private readonly string _ro2; private readonly int _ro3; public Bar() : base() { } public bar(int arg) : base(arg) { _ro3 = arg; _ro2 = "read only : " + arg; }` basicly, if the value of readonly fields is determined by the constructor argument, you can put the field's initialization on the constuctor. And if not, you can put the initialization just like the first read only field above (_ro1). – Moch Yusup May 02 '13 at 01:30
  • Your answer was suggesting moving initialization code out of the constructor to a virtual method. One can initialize read-only fields in a constructor or field initializer, but one can also do it with a virtual method, *if* one passes the fields in question as `ref` or `out` parameters to the method in question. BTW, one thing I'd really like to see in vb.net and C# would be a means of defining a field or pseudo-field that would be initialized with the value in a constructor parameter, and could be used in later field initializers. Something like: ... – supercat May 02 '13 at 14:48
  • ...`class Thing {int ArrSize = (int Size); int[] MyData = new int[ArrSize]; Thing(int Size) {};}` where the `(int Size)` initialization of `ArrSize` would indicate that any constructor for this type will either have an `int` parameter called `Size` or chain to one that does, and the value passed to that parameter should be used to initialize `ArrSize`. To my mind, if a field will be set once to something that can be computed based on constructor parameters, and never modified thereafter, it would be cleaner to combine the declaration and initialization than to write then in different places. – supercat May 02 '13 at 14:53