views:

12020

answers:

12

Imagine a base class with many constructors and a virtual method

public class Foo
{
   ...
   public Foo() {...}
   public Foo(int i) {...}
   ...
   public virtual void SomethingElse() {...}
   ...
}

and now I want to create a descendant class that overrides the virtual method:

public class Bar : Foo 
{
   public override void SomethingElse() {...}
}

And another descendant that does some more stuff:

public class Bah : Bar
{
   public void DoMoreStuff() {...}
}

Do I really have to copy all constructors from Foo into Bar and Bah? And then if I change a constructor signature in Foo, do I have to update it in Bar and Bah?

Is there no way to inherit constructors? Is there no way to encourage code reuse?

+25  A: 

Yes, you will have to implement the constructors that make sense for each derivation and then use the base keyword to direct that constructor to the appropriate base class or the this keyword to direct a constructor to another constructor in the same class.

If the compiler made assumptions about inheriting constructors, we wouldn't be able to properly determine how our objects were instantiated. In the most part, you should consider why you have so many constructors and consider reducing them to only one or two in the base class. The derived classes can then mask out some of them using constant values like null and only expose the necessary ones through their constructors.

Update

In C#4 you could specify default parameter values and use named parameters to make a single constructor support multiple argument configurations rather than having one constructor per configuration.

Jeff Yates
i think having to copy the signature of one constructor is too many. In my real situation i had one constructor, and i do not want to have to copy it. Then i have to change it in two places.
Ian Boyd
This is why upfront design is important. You shouldn't be coding with 100% conviction that it all has to change.
Jeff Yates
+8  A: 

Yes, you have to copy all 387 constructors. You can do some reuse by redirecting them:

  public Bar(int i): base(i) {}
  public Bar(int i, int j) : base(i, j) {}

but that's the best you can do.

James Curran
+19  A: 

387 constructors?? That's your main problem. How about this instead?

public Foo(params int[] list) {...}
Kon
Bingo, people don't use params as much as they should
Marcus King
To be honest, I've never used them myself in any production code. I usually have List<int> or some collection I pass. I long for the day where I get to leverage params. :)
Kon
This is not an answer to the actual question which is about having to duplicate constructors in child classes.
trampster
If you want to nit pick, one of questions was "Do i really have to copy all 387 constructors from Foo into Bar and Bah?" To which the answer is no, because you wouldn't (in a reasonable situation) have 387 constructors. I don't blindly answer - I try to provide good solutions, as should you.
Kon
Does your answer change if there was just one constructor?
Ian Boyd
I'd like to think SO would encourage people to provide a better solution to a higher level problem the questioner did not think to ask, rather than downvoting them for it.
annakata
+1  A: 

Too many constructors is a sign of a broken design. Better a class with few constructors and the ability to set properties. If you really need control over the properties, consider a factory in the same namespace and make the property setters internal. Let the factory decide how to instantiate the class and set its properties. The factory can have methods that take as many parameters as necessary to configure the object properly.

tvanfosson
Having to copy one constructor signature is too many.
Ian Boyd
If you require your class to be immutable then you don't want to expose properties. Because then your class has state.
trampster
@Daniel, that's why I suggested the factory pattern using internal setters. In that way the setters are only exposed to the class that creates the object and the object can maintain (for all intents and purposes) its immutability.
tvanfosson
+2  A: 

The problem is not that Bar and Bah have to copy 387 constructors, the problem is that Foo has 387 constructors. Foo clearly does too many things - refactor quick! Also, unless you have a really good reason to have values set in the constructor (which, if you provide a parameterless constructor, you probably don't), I'd recommend using property getting/setting.

Chris Marasti-Georg
Not addressing the real question. And doesn't help if class needs immutable state.
trampster
Hence the "unless you have a good reason". The point is, any class with 387 constructors does too much.
Chris Marasti-Georg
+1  A: 

No, you don't need to copy all 387 constructors to Bar and Bah. Bar and Bah can have as many or as few constructors as you want independent of how many you define on Foo. For example, you could choose to have just one Bar constructor which constructs Foo with Foo's 212th constructor.

Yes, any constructors you change in Foo that Bar or Bah depend on will require you to modify Bar and Bah accordingly.

No, there is no way in .NET to inherit constructors. But you can achieve code reuse by calling a base class's constructor inside the subclass's constructor or by calling a virtual method you define (like Initialize()).

C. Dragon 76
You shouldn't call virtual methods in constructors - a subclass will not have run its constructor at the time the virtual method is called.
Chris Marasti-Georg
Yes, that's probably good advice. You could have the virtual Initialize pattern be called by callers after construction though. The pattern would be Bar bar = new Bar(); bar.Initialize();
C. Dragon 76
That is good advice, like Color.FromArgb.
Ian Boyd
+1  A: 

You may be able to adapt a version of the C++ virtual constructor idiom. As far as I know, C# doesn't support covariant return types. I believe that's on many peoples' wish lists.

Greg D
This sounds interesting, although i don't know what covariant means. :(
Ian Boyd
+5  A: 

Don't forget that you can also redirect constructors to other constructors at the same level of inheritance:

public Bar(int i, int j) : this(i) { ... }

dviljoen
+3  A: 

As Foo is a class can you not create virtual overloaded Initialise() methods? Then they would be available to sub-classes and still extensible?

public class Foo
{
   ...
   public Foo() {...}

   public virtual void Initialise(int i) {...}
   public virtual void Initialise(int i, int i) {...}
   public virtual void Initialise(int i, int i, int i) {...}
   ... 
   public virtual void Initialise(int i, int i, ..., int i) {...}

   ...

   public virtual void SomethingElse() {...}
   ...
}

This shouldn't have a higher performance cost unless you have lots of default property values and you hit it a lot.

Keith
Yes, that is a very good idea; although i would probably have initialize a static method that returns a class
Ian Boyd
+4  A: 

Too bad we're kind of forced to tell the compiler the obvious:

Subclass(): base() {}
Subclass(int x): base(x) {}
Subclass(int x,y): base(x,y) {}

I only need to do 3 constructors in 12 subclasses, so it's no big deal, but I'm not too fond of repeating that on every subclass, after being used to not having to write it for so long. I'm sure there's a valid reason for it, but I don't think I've ever encountered a problem that requires this kind of restriction.

Resharper makes this easy! (Alt+Insert, Constructors)
Callum Rogers
A: 

Is it possible to say that some macromagic would solve this problem with copy-paste code manually, just make the compiler do it for you. Or will everybody hate this solution just because i used the word "macro"? ;)

Boll
A: 
public class BaseClass
{
    public BaseClass(params int[] parameters)
    {

    }   
}

public class ChildClass : BaseClass
{
    public ChildClass(params int[] parameters)
        : base(parameters)
    {

    }
}
Pavlo Neyman