Ian
Ian

Reputation: 30813

Forcing partial base Initialization (and methods) in Inherited Class Constructor C# (like abstract does to methods) - work around to do it

I am having a C# abstract class which have some methods to be implemented by its children.

Though it is so, the initialization values for those children consist of two parts: one which is the same as the parent, and another one which is unique to the children.

public abstract class parentClass {
    public abstract bool IsInputValid(string input); //children must implement this
    public parentClass () {
       //Some shared initialization
    }
}

If the class is not abstract we could do something like this to implement that

public class parentClass {
    public parentClass (string input) {
       //Some shared initialization
    }
}

public class childClass : parentClass {
    public childClass (string input) : base (input) {
       //Some unique initialization
    }
}

But that cannot be done using abstract class and some more, the method not need not to be implemented (since it is not abstract).

So I am in a dilemma here. On one hand, I want to have some base initialization called and on the other, I also want to have some methods enforced.

So my question is, how do we normally implement such case? On one hand it is enforcing some base initialization, and on another some methods.

Note: I am new to abstract class so I would be glad to receive any inputs regarding it.

Where do I declare wrongly (if any)? If we cannot do so, is there a way to get around to produce the same result (that is, to enforce the child class to use certain signature for constructor)?

Upvotes: 1

Views: 1493

Answers (4)

Lasse V. Karlsen
Lasse V. Karlsen

Reputation: 391416

There should be no need to enforce this. You say that the base class has some common initialization and the child classes have their own specialized initialization as well.

This is enforced already, if you have this:

public abstract class Base
{
    protected Base(int value) { ... }
}

Then you have a couple of guarantees:

  • Nobody can construct an object of the type Base since it is abstract
  • Nobody can construct an object that inherits from Base without indirectly calling the only existing constructor of Base, that takes an int value parameter.

The last part there is important.

A child class can deal with this type of base constructor in at least three ways:

  • It can provide a constructor that looks identical save the name of it, just passing the value down to the base constructor:

    public class Child : Base
    {
        public Child(int value) : base(value) { ... }
    }
    
  • It can provide a constructor that has this parameter but has additional parameters to the child class constructor as well:

    public class Child : Base
    {
        public Child(int value, string other) : base(value) { ... }
    }
    
  • It can provide a constructor that doesn't have the parameter to the base class, but manages to compute this parameter:

    public class Child : Base
    {
        public Child(string other) : base(other.Length) { ... }
    }
    

The last part also handles the case where the child constructor has no parameters at all:

public class Child : Base
{
    public Child() : base(new Random().Next(100)) { ... }
}

Regardless of which approach you use, it is impossible to call the base class constructor without passing a value for that parameter, hence you have enforce the following:

  • Child classes has to be aware of the base class constructor and its parameter

But you cannot, and should not, try to enforce the presence of a particular constructor with a specific signature.


Now, having said that, what if you want to create some sort of common way to construct two distinct child classes, that has such different constructors, in such a way that code that uses them doesn't need to know the specifics of either constructor?

Enter the factory pattern (Wikipedia):

In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor.

(quoted text copied from entry paragraph in the Wikipedia-article)

Here's a way to abstract away the presence and knowledge of such different constructors and child classes:

void Main()
{
    Test(new Child1Factory());
    Test(new Child2Factory());
}

public void Test(IBaseFactory baseFactory)
{
    Console.WriteLine("In Test(...");
    var b = baseFactory.Create();
}

public class Base
{
    public Base(int value)
    {
        Console.WriteLine($"Base.ctor({value})");
    }
}

public interface IBaseFactory
{
    Base Create();
}

public class Child1 : Base
{
    public Child1(int value) : base(value)
    {
        Console.WriteLine($"Child1.ctor({value})");
    }
}

public class Child1Factory : IBaseFactory
{
    public Base Create() => new Child1(42);
}

public class Child2 : Base
{
    public Child2(string name) : base(name.Length)
    {
        Console.WriteLine($"Child2.ctor({name})");
    }
}

public class Child2Factory : IBaseFactory
{
    public Base Create() => new Child2("Meaning of life");
}

Pay special attention to the Test(...) method, as this has no knowledge of which Base child it will get, nor how to construct such an object. If you later on add new child types from Base, you will have to provide new factories as well but existing code that uses these factories should not need to be changed.

If you want a simpler factory pattern all you have to do is replace the interface and factory classes with a delegate:

void Main()
{
    Test(() => new Child1(42));
    Test(() => new Child2("Meaning of life"));
}

public void Test(Func<Base> baseFactory)
{
    Console.WriteLine("In Test(...");
    var b = baseFactory();
}

Final note here. Since the factory pattern means you will have to create a different type that does the actual construction of the object you can enforce the signature of that other type, either by

  • Adding parameters to the Create method on the factory interface
  • Specifying a delegate that has parameters to the factory delegate

This means you can enforce the signature of "the creation process". Still, you cannot enforce the presence or signature of a particular constructor, but the constructor is just a means to an end, create an object, and with the factory pattern you can actually formalize this pattern in your code and thus you should get what you want.

Upvotes: 1

jHilscher
jHilscher

Reputation: 1868

Since you can't override constructors in c#, you cannot enforce the existence of a certain constructor in the derived class .

This means:

  • a constructor cannot be abstract, virtual etc
  • constructors aren't polymorphically

Upvotes: 1

Shazi
Shazi

Reputation: 1569

You cannot have an abstract constructor, but neither is there any need to. All you need to do is remove the "abstract" keyword from your parentClass and you should be good to go.

Upvotes: 0

nvoigt
nvoigt

Reputation: 77304

You cannot enforce the signature or even existence of constructors of your derived classes. (or any class for that matter)

I'm afraid that's the end of the story. You aren't doing anything wrong, it's just not possible.

Upvotes: 1

Related Questions