-1

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!

EProgrammerNotFound
  • 2,403
  • 4
  • 28
  • 59
  • 5
    You can't override constructors... and it's not clear what your `StackOverflow` class *has* in it... – Jon Skeet Jan 08 '14 at 17:20
  • 5
    You should not prefix class name with `I`, even if the class is abstract. – MarcinJuraszek Jan 08 '14 at 17:21
  • Why is your class `abstract`? It is not obvious from the post. – John Alexiou Jan 08 '14 at 17:21
  • I came from Delphi programming, maybe there is another way to do what I want... – EProgrammerNotFound Jan 08 '14 at 17:22
  • @JonSkeet The Activator is not able to "see" the abstract constructor? I am obligated to write it? – EProgrammerNotFound Jan 08 '14 at 17:25
  • 1
    Well you can't create an instance of just an abstract class. There *has* to be a concrete derived class. Do you have such a class? It would really help if you'd provide a short but *complete* program demonstrating the problem. – Jon Skeet Jan 08 '14 at 17:28
  • @Matheus See http://stackoverflow.com/questions/223058/how-to-inherit-constructors Also, if you were trying to activate with the parameterless constructor, that would work fine since you always have one available. Since you're trying to call one with parameters, it cannot be found since constructors are not inherited. – Steve Jan 08 '14 at 17:40
  • @MatheusFreitas some people say that the second `C` in `SSCCE` stands for `Compilable`. Wonder why? – Julián Urbano Jan 08 '14 at 17:47
  • same problem as said, `class Duck`'s constructor is called `public Duck()` - a derived `class Donald : Duck`'s constructor is called `public Donald() : base()` that implicitly calls `public Duck()` because of `: base()`. the code you provide has never been compiled without errors. – metadings Jan 08 '14 at 17:48
  • @MatheusFreitas where are `Habitat` and `IJob` defined? And how do you magically multiply `2` and `makeLittleDuck(typeof(MallarDuck), DefineHabitat)`, which returns a `Duck`? – Julián Urbano Jan 08 '14 at 17:56
  • sorry, i was wrong with my second answer, works just for non-abstract classes, to not define any constructor so that the base class constructors are used. – metadings Jan 08 '14 at 18:18

2 Answers2

2

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);
    }
}
metadings
  • 3,798
  • 2
  • 28
  • 37
1

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.

Julián Urbano
  • 8,378
  • 1
  • 30
  • 52
  • The problem is that I need to pass the parameters in the constructor, only there it can be Write, otherwise, it will be just read! – EProgrammerNotFound Jan 08 '14 at 18:13
  • The generic type T also don't allow me to use the overloaded constructor T(this, Parameters); – EProgrammerNotFound Jan 08 '14 at 18:31
  • @MatheusFreitas Looking at your code, seems that your constructors only assign/initialize fields, so there is no reason why you can't do that in the `createAnotherX` methods. Note that you can't just instantiate those classes elsewhere, it must be done through `createAnotherX` because the default constructor is protected. – Julián Urbano Jan 08 '14 at 18:45
  • Ok, I will always create a new instance of Parent by using the static methods. Is this a good desing? – EProgrammerNotFound Jan 08 '14 at 18:56
  • @MatheusFreitas no, you don't, you only need to initialize them in the `createAnotherX` methods. The default constructor does nothing. See the edited answer – Julián Urbano Jan 08 '14 at 18:57
  • I understood that, now I wonder if there is an easier solution...I prefer to avoid the static aproach – EProgrammerNotFound Jan 08 '14 at 18:58
  • I'm not even sure why you want to do this, but if you have several child classes, all constructed with the same parameters, then why not write those constructors? Even if they just delegate on the base constructor. All you're doing here is to avoid writing some code for the sake of simplicity, but not for the sake of portability. Note that there is no way of using your classes elsewhere if it's not through `createAnotherX`. So it's just a matter of how much complicated you want it to be for the sake of clarity (if any). – Julián Urbano Jan 08 '14 at 19:01
  • What else would you suggest then? Here is the problem: There are tasks that need to execute another tasks in the middle of it's execution. The first task needs to wait the second task to finish, for example: Let's say that the first task writes to disk, then, the disk needs to be cleared sometimes, so the first task creates a task to selectively delete some files. – EProgrammerNotFound Jan 08 '14 at 19:07
  • So? Can't you just instantiate an object of the second class (directly or through some static syntax-sugar), and run it? – Julián Urbano Jan 08 '14 at 19:18