Dynamically instantiate class

2k Views Asked by At

I am trying to dynamically instantiate classes descendant of an abstract class, but the activator is forcing me to override the constructor to every descendant. Is there a way to avoid this?

P.S: I need to pass the parameters in the constructor, only there it can be Write, otherwise, it will always be read!

2

There are 2 best solutions below

9
On BEST ANSWER

Constructors are not inherited, so if you must instantiate a child object through a constructor with those parameters, then you need to write a new constructor in the child class that basically does base(p1, p2, ..., pn).

Looking at your code, seems that your constructors only assign/initialize fields, so there is no reason why you can't do that somewhere outside the constructor, as long as you control it appropriately. This might be a long shot, but I feel this is more what you want:

public abstract class Parent
{
    protected bool foo
    {
        get;
        private set; // just set the property setter as private
    }

    protected Parent() {
        // protected so all instances are created through createAnotherX
        // note that nothing is initialized here!
    }

    public abstract int Enter(); // To override in child classes

    // Option 1: use generics
    public static T createAnother1<T>(bool f) where T : Parent, new()
    {
        T p = new T();
        p.foo = f;

        return p;
    }
    // Option 2: use the runtime type
    public static Parent createAnother2(Type t, bool f)
    {
        Parent p = Activator.CreateInstance(t) as Parent;
        p.foo = f;

        return p;
    }

    // Examples
    public static void Main()
    {
        Parent p1 = Parent.createAnother1<Child>(true);
        Parent p2 = Parent.createAnother2(typeof(Child), true);
    }
}
// the child class only has to worry about overriding Enter()
public class Child : Parent
{
    public override int Enter()
    {
        return 1;
    }
}

Note that you must instantiate objects through the createAnotherX because the default constructor is protected. In addition, as per your comment, see that the property is defined so that only you can set values, which is what you tried to do in your code when explicitly ignoring the setter.

2
On

Is there a way to avoid this?

Short answer: Yes, when you define no constructor in your derived class, the (abstract) base class constructors are used. When you define one, you have to redefine all constructors.
Not without a workaround pattern.

EDIT: Sorry, I'm wrong that does only work for parameterless constructors.

How you can achive your goal,

is using a protected parameterless constructor and a static Create method:

public abstract class Duck {

    private string _DucksParam0;

    public string DucksParam0 {
        get {
            return  _DucksParam0;
        }
    }

    // Using protected, this constructor can only be used within the class instance
    // or a within a derived class, also in static methods
    protected Duck() { }

    public static DuckT Create<DuckT>(string param0)
        where DuckT : Duck
    {
        // Use the (implicit) parameterless constructor
        DuckT theDuck = (DuckT)Activator.CreateInstance(typeof(DuckT));

        // This is now your "real" constructor
        theDuck._DucksParam0 = param0;

        return theDuck;
    }

}

public class Donald : Duck {
}

Usage (dotnetfiddle):

public class Program
{
    public void Main()
    {
        Duck d =  Duck.Create<Donald>("Hello  World");
        Console.WriteLine(d.DucksParam0);
    }
}