66

I am creating an abstract class. I want each of my derived classes to be forced to implement a specific signature of constructor. As such, I did what I would have done has I wanted to force them to implement a method, I made an abstract one.

public abstract class A
{
    abstract A(int a, int b);
}

However I get a message saying the abstract modifier is invalid on this item. My goal was to force some code like this.

public class B : A
{
    public B(int a, int b) : base(a, b)
    {
        //Some other awesome code.
    }
}

This is all C# .NET code. Can anyone help me out?

Update 1

I wanted to add some things. What I ended up with was this.

private A() { }

protected A(int a, int b)
{
    //Code
}

That does what some folks are saying, default is private, and the class needs to implement a constructor. However that doesn't FORCE a constructor with the signature A(int a, int b).

public abstract class A
{
    protected abstract A(int a, int b)
    {


    }
}

Update 2

I should be clear, to work around this I made my default constructor private, and my other constructor protected. I am not really looking for a way to make my code work. I took care of that. I am looking to understand why C# does not let you do this.

Anthony D
  • 10,877
  • 11
  • 46
  • 67
  • It was a typo, (should have been int b) but my answer was very similar to Jamie which is why I deleted mine. – BFree Feb 02 '09 at 21:49
  • Today POO worlds doesn't understand the concept of overriding a shared (constructors are shared methods, event if .net means it's not shared, in reality it's a shared method because you can call it everywhere and it doesn't need an instance). So overriding shared It's a strange feature that few languages (like Haskell) understand. – Toto Nov 03 '11 at 23:01

9 Answers9

56

You cannot have an abstract constructor because abstract means you must override it in any non-abstract child class and you cannot override a constructor.

If you think about it, this makes sense, since you always call the constructor of the child class (with the new operator) and never the base class.

Generally speaking, the only way in C# to enforce a specific constructor signature is by using the new() generic constraint, which enforces the existence of a parameterless constructor for the type parameter.

Tamas Czinege
  • 118,853
  • 40
  • 150
  • 176
  • 1
    Can you give an example with `new()`? Isn't that the dangerous keyword that hides inherited member or it's something else? – jeromej Oct 01 '18 at 13:01
  • Years later: jeromej is referring to the keyword `new`, which is used to hide (NOT override, though the goal and outcome are simiilar) a member of the base class which is not virtual or abstract. That is different than the `new()` constraint. – Sinjai Sep 08 '21 at 05:21
26

Change that constructor in class A to

protected A(int a, int b)
{
    // Some initialisation code here
}

Then your subclasses will have to use it, as there is no default constructor.

They can, however, still change the actual signature of the constructor. There is no way of forcing a subclass to use a specific signature for its constructor as far as I know. I'm pretty sure constructors can't be abstract.

What exactly do you need this for? We might be able to suggest a work around for this.

Jamie Penney
  • 9,424
  • 3
  • 29
  • 37
7

Although you can't override constructors, and therefore can't define an abstract constructor, you can place an abstract factory method in your abstract base class. All the derived classes would need to override that.

public abstract class A 
{ 
    abstract A MakeAInstance(int a, int b); 
} 

public class B : A 
{ 
    // Must implement:
    override A MakeAInstance(int a, int b) {
        // Awesome way to create a B instance goes here
    }
} 
John Saunders
  • 160,644
  • 26
  • 247
  • 397
5

Multiple reasons:

1) Constructors are not inherited thus you cannot override them.

2) The constructor is a static member function since it dont need a specific instance to be called. Abstract implies "virtual" which means that the implementation can vary depending on how a specific instance is subclassed, which is the opposite of the intention of the meaning of the "static" keyword.

Mats
  • 67
  • 1
  • 1
  • 2
    I disagree with your statement of a constructor is a static member, it does need an instance to be called (since you can access instance methods, fields, etc.). The `new` keyword instanciates the object, and then the constructor gets called, the constructor itself doesn't "construct" the object. – Matthew Apr 20 '12 at 15:54
  • The constructor is an instance method (i.e. a non-static method), as seen from a CIL perspective. It might look like: `.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ... }` So its name is `.ctor`, it is `instance` not `static`, and its return type is `void`. (Its accessibility maybe be different from `public`, and its parameter list may contain some args.) – Jeppe Stig Nielsen Apr 01 '15 at 15:28
4

You cannot enforce constructor signature, as each derived class may (must!) define its own constructor(s), and they may take any parameters they like.

If you need to pass a given set of variables to an object of a derived class, define an abstract method which needs to be implemented by derived classes. If the classes do not implement the abstract method, you will get a compiler error.

devio
  • 36,858
  • 7
  • 80
  • 143
1

hope this will help someone newb as i am i was looking to make a "normal" public class with a ctor that takes argument and then i needed to make it a child class so i needed an empty ctor for it.

i didnt know this before: if you make a protected ctor then the child class sees it but the rest of the program dont see it (i guess my confusion is since in asp.net i see all the protected in the aspx page which inherits from the cs...)

bresleveloper
  • 5,940
  • 3
  • 33
  • 47
  • 1
    Actually the .aspx and .aspx.cs both define the same class. So the .aspx page is not "inheriting" the class in the .aspx.cs code, (despite the fact that it is referred to in the `<%Page%>` directive as "Inherits") but is actually defining a partial to that same class. – CptRobby Aug 22 '13 at 21:25
0

not sure if this helps - but i feel this would be a solution to your problem:

public class A
{
  public A(int a, int b)
  {
    DoSomething(int a, int b);
  }

  virtual public void DoSomething(int a, int b)
  {

  }
}

public class B : A
{
  override public void DoSomething(int a, int b)
  {
    //class specific stuff
  }
}

with the result that you can call a constructor with the required arguments in any derived class with the correct behaviour.

mo.
  • 17
  • 1
0

All subclasses always can specify their own constructor as long as they call a constructor of the superclass - so there is no way of forcing the a class to have a specific constructor (At least, that is the way it works in Java). You could see of using a factory pattern will get you somewhere - you could define a factory method in an interface - but you'll need a separate factory class as your abstract base class does not know the actual class of the object that needs to be created.

However: maybe adding a more concrete example of the issue you are having might prompt other/better responses. Are you looking for some generic instantiation code, or are you concerned specific settings on the abstract base class have to be done?

If you are just concerned about initialization that has to be done by the abstract class, create a method to do so, and document the usage of that method.

Simon Groenewolt
  • 10,607
  • 1
  • 36
  • 64
0

C# 11 and .NET 7 have introduced static virtual members in interfaces, which can be used (albeit in a contrived way) to enforce a factory method with a given signature.

public interface IBase<TDerived> where TDerived : Base<TDerived>, IBase<TDerived>
{
    public static abstract TDerived CreateInstance(int a, int b);
}

public abstract class Base<TDerived> where TDerived : Base<TDerived>, IBase<TDerived>
{
    protected Base(int a, int b) { }
}

And then, in some other assembly:

public class Derived : Base<Derived>, IBase<Derived>
{
    static Derived IBase<Derived>.CreateInstance(int a, int b)
    {
        return new(a, b);
    }

    public Derived(int a, int b) : base(a, b) { }
}

This solution is admittedly a bit code-smelly with an private protected base class constructor and a separate interface that must be implemented. Unfortunately, there are no static abstract/static virtual methods in classes (yet?), but despite the smell this solution is functional.

I am using this pattern to create managed class instances from unmanaged data. I have an extensible (non-generic) Base class and new Derived classes may be added at any time (even from other assemblies), so I can't deterministically select the right class to instantiate at compile-time, but I can use runtime data to determine this. My Base class holds a static Dictionary<int, Func<int, int, Base>>. Then in the Base<TDerived> class constructor, I populate that dictionary (new keys are added to the dictionary at the first instantiation of a Derived class).

protected Base(int a, int b) : base(a, b) // Base<TDerived> ctor, calls non-generic Base ctor
{
    // cache factory functions
    _ = instanceCreators.TryAdd(GetKey(a, b), TDerived.CreateInstance);
    // Func is covariant and accepts the more derived return type
    // GetKey maps the unmanaged data to a unique key
}

From there, my Base class can return full instances of any of the Derived classes:

public static Base GetDerived(int a, int b) // in Base class
{
    return instanceCreators[GetKey(a, b)](a, b); // calls Derived class constructor
}

Because new Derived types can be added, even from outside the assembly, there isn't a more elegant solution to creating the instances I need from the Base class. Hopefully static abstract methods will be extended to abstract classes as well so the interface can be removed, at least. This approach will work for the time being.

Edit: Somehow, I overlooked the introduction of the private protected access modifier, which is a much better fit for this absurd approach than using internal.

Edit 2: On further reflection, there's no need for the non-generic Base class in the general case. I just needed it for caching the Func that actually yields the Derived instances. Removing the intermediary, non-generic Base class makes the general case implementation simpler.

monkey0506
  • 2,489
  • 1
  • 21
  • 27