1

Is it possible to get a new instance of the current derived class that is calling a function of the base abstract class? For example:

class Bar1 : Foo
{

}
class Bar2 : Foo
{

}

abstract class Foo
{
    public Foo CreateAnotherInstance()
    {
        return new Bar1/Bar2();   // depending on the calling derived class
    }
}

Should lead to:

Bar1 bar1 = new Bar1();
Bar2 bar2 = new Bar2();
Foo bar1_2 = bar1.CreateAnotherInstance();  // Should be a new Bar1 instance
Foo bar2_2 = bar1.CreateAnotherInstance();  // Should be a new Bar2 instance

The only way i've found is to create the instance is an abstract method, where the instance is created in each derived class like:

class Bar1 : Foo
{
    public override Foo CreateAnotherInstance()
    {
        return new Bar1();
    }
}

class Bar2 : Foo
{
    public override Foo CreateAnotherInstance()
    {
        return new Bar2();
    }
}

abstract class Foo
{
    public abstract Foo CreateAnotherInstance();
}

But in this way, i have to create the method for each derived class.

Is there a simpler solution for this problem available?

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • why you need that at all? `bar1` is already an instance of `Bar1` – Rahul Nov 16 '17 at 11:56
  • 4
    `return Activator.CreateInstance(GetType());` will work if the derived class has a public parameterless constructor. – René Vogt Nov 16 '17 at 12:00
  • Why not to use constructor? – Chetan Nov 16 '17 at 12:00
  • @Rahul --> I make something like a Treewalker, the current bar1-object contains some data with a link --> a deeper Bar1-object should be generated with this link and the data behind –  Nov 16 '17 at 12:01
  • @Chetan Ranpariya --> Can you please explain how to make this? –  Nov 16 '17 at 12:03
  • 2
    https://stackoverflow.com/questions/2451336/how-to-pass-parameters-to-activator-createinstancet – mjwills Nov 16 '17 at 12:08
  • Thank you René Vogt, that's the solution, and thank you mjwills, for the version with parameter –  Nov 16 '17 at 12:10
  • 2
    Yes, see mjwills' link or the [MSDN](https://msdn.microsoft.com/en-us/library/system.activator.createinstance(v=vs.110).aspx) – René Vogt Nov 16 '17 at 12:10
  • 1
    @Pedro you should add the solution as a self answer and not in the original post. – Nkosi Nov 16 '17 at 12:15
  • Oh sorry, ok i'll add that –  Nov 16 '17 at 12:17

2 Answers2

1

Thanks to René Vogt and mjwills for giving the answer:

Using

(Foo)Activator.CreateInstance(GetType()); 

So change the abstract class to:

abstract class Foo
{
    public Foo CreateAnotherInstance()
    {
        return (Foo)Activator.CreateInstance(GetType());
    }
}

If the constructor isn't parameterless:

(Foo)Activator.CreateInstance(GetType(), para1, para2, ...); 
1

Whilst Activator.CreateInstance is a good way to do this, I'm not sure this is a method that belongs in the base abstract class, or indeed any of these classes. Doesn't this break polymorphism? Or at least the Liskov substitution principle?

In any case, as an alternative, how about just creating a simple method that will work for any type, not just the ones above. e.g.

public static T CreateNew<T>(params object[] parms)
{
  return (T) Activator.CreateInstance(typeof(T), parms);
}

This also allows you to pass in the constructor parameters if there are any.

bornfromanegg
  • 2,826
  • 5
  • 24
  • 40