Is it possible to enforce a compile-time contract on derived classes requiring implementation of a constructor (with parameter)?
I have a base class with a constructor requiring a parameter:
public class FooBase
{
protected int value;
public FooBase(int value) { this.value = value; }
public virtual void DoSomething() { throw new NotImplementedException(); }
}
I'd like to force derivations of my base class to implement the same constructor:
public class Foo : FooBase
{
public Foo(int value) : base(value) { }
public override void DoSomething() { Console.WriteLine("Foo: {0}", value); }
}
If no constructor is implemented, derived classes causes a compiler error because there is no default constructor in the base class:
// ERROR: 'Does not contain a constructor that takes 0 arguments'
// Adding default constructor in FooBase eliminates this compiler error, but
// provides a means to instantiate the class without initializing the int value.
public class FooBar : FooBase
{
public override void DoSomething() { Console.WriteLine("FooBar: {0}", value); }
}
Adding a default constructor, FooBar(), in the derived class silences the compiler error, but provides a dangerous means of instantiating FooBar without the required base class int value being initialized. Because I'm using a factory (see below), silencing the compiler error only results in a run-time error later. I'd like to force FooBar to implement FooBar(int)
INTERESTING OBSERVATION:
If a default constructor, FooBase(), is added to FooBase, then it is 'inherited' by derived classes that do not provide a constructor:
- Foo does not inherit the default constructor because it supplies an explicit constructor.
- FooBar DOES inherit FooBase().
HOWEVER, the same is not true with the non-default constructor FooBase(int)!
- Foo MUST explicitly implement FooBase(int) and call base(int).
- FooBar FAILS to 'inherit' the non-default constructor the same way that a default constructor is inherited!
I do not want a default constructor in the base class because instances are created using a factory method that supplies a needed "settings" parameter. That factory method is not illustrated here (which uses the Activator.CreateInstance() method).
Here is the way derived classes should be instantiated:
static void Main(string[] args)
{
FooBase myFoo = new Foo(4); // Works, since Foo(int) is implemented.
// ERROR: 'Does not contain a constructor that takes 1 arguments'
FooBase myFooBar = new FooBar(9); // Fails to compile.
}
Because I am using a factory–not direct instantiation as shown–there is no compiler error. Instead, I get a runtime exception: 'Constructor on type not found.'
Unworkable solutions:
- Interfaces do not support constructors.
- Constructors cannot be virtual or abstract.
It appears that supplying a base class cannot enforce a contract on constructors.
Work-around:
- Provide a default constructor in base class along with property to pass settings parameter.
Best Answer
This is incorrect - constructors in general are never inherited. A default constructor is automatically provided for a class that does not provide any other constructor implementation.
You could put in a constraint on an interface that provides an Init() method for you: