Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force derived class to implement base class constructor with parameter(s)

Tags:

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:

  1. Foo does not inherit the default constructor because it supplies an explicit constructor.
  2. FooBar DOES inherit FooBase().

HOWEVER, the same is not true with the non-default constructor FooBase(int)!

  1. Foo MUST explicitly implement FooBase(int) and call base(int).
  2. 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.
like image 476
Kevin P. Rice Avatar asked Jul 02 '11 21:07

Kevin P. Rice


People also ask

Can we pass parameters to base class constructor through derived?

To pass arguments to a constructor in a base class, use an expanded form of the derived class' constructor declaration, which passes arguments along to one or more base class constructors. Here, base1 through baseN are the names of the base classes inherited by the derived class.

How do you call a base class constructor from a derived class?

How to call the parameterized constructor of base class in derived class constructor? To call the parameterized constructor of base class when derived class's parameterized constructor is called, you have to explicitly specify the base class's parameterized constructor in derived class as shown in below program: C++

Does a derived class use base constructor C++?

In C++, a derived-class constructor always invokes a constructor for the base class. If an explicit invocation does not appear in the member-initializer list, there is an implicit call to the default constructor.

Can a constructor be inherited by a derived class from the base class?

In inheritance, the derived class inherits all the members(fields, methods) of the base class, but derived class cannot inherit the constructor of the base class because constructors are not the members of the class.


2 Answers

If a default constructor, FooBase(), is added to FooBase, then it is 'inherited' by derived classes that do not provide a constructor:

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:

public interface IInit {    void Init(int someValue); }  public class FooBase : IInit {    .. } 
like image 70
BrokenGlass Avatar answered Oct 28 '22 00:10

BrokenGlass


Did you try

public class FooBase {   protected int value;   private FooBase(){}   public FooBase(int value) { this.value = value; }   public virtual void DoSomething() { throw new NotImplementedException(); } } 

the private constructor prevents the option of parameter-less constructor

like image 41
Ahmed Magdy Avatar answered Oct 28 '22 01:10

Ahmed Magdy