1

I have an Animal class, and two derived classes: Lion and Ant.

I have a method that takes in an Animal type and I want to return a new instance of the derived type of the animal passed to the function (i.e. a new instance of Lion).

public Animal Reproduce(Animal p_animal)
{
    Type animalType = p_animal.GetType();

    if (SameSpecies(p_animal)) 
        return new animalType(RandomName());
}
Sowdowdow
  • 409
  • 1
  • 3
  • 13
  • 2
    [Duplicate](https://stackoverflow.com/questions/752/get-a-new-object-instance-from-a-type) – Peter Schneider Nov 05 '18 at 17:31
  • 3
    Possible duplicate of [Get a new object instance from a Type](https://stackoverflow.com/questions/752/get-a-new-object-instance-from-a-type) – GSerg Nov 05 '18 at 17:34
  • The reproduce method should be a part of the individual classes. You should have a reproduce method for a Lion and a reproduce method for an Ant. – Zohar Peled Nov 05 '18 at 17:34
  • Can you please specify what's not working with the code you've shown? And what does `SameSpecies` do? Since it only takes in one argument, it returns `true` if `p_animal` is the same species as *what*? – Rufus L Nov 05 '18 at 17:37

3 Answers3

4

There are several ways to achieve this, but what I would suggest is that you create an abstract Reproduce method on your Animal class and implement it in the derived types. For instance:

public abstract class Animal
{
    /* .. other stuff .. */
    public abstract Animal Reproduce();
    public string RandomName() { /* ... */ }
}

public class Lion : Animal
{
    /*... other stuff .. */
    public override Animal Reproduce() => new Lion(RandomName());
}

That way you can add any future logic in the Reproduce method specific to a certain Animal

KMoussa
  • 1,568
  • 7
  • 11
  • That was my initial solution, but at the end I was rewriting the same thing in every derivated types, and as I've a lot of derivated types it is not very maintenable. – Sowdowdow Nov 05 '18 at 17:50
  • Sure .. but I'd suggest even if you go with reflection, make it a virtual method on Animal that calls `Activator.CreateInstance`, this way you can still customize the behaviour in specific derived types within the type itself – KMoussa Nov 05 '18 at 18:02
3

Since you don't know the type at compile time, you will have to use Reflection. What you are trying to achieve can be done with:

return (Animal)Activator.CreateInstance(animalType, RandomName());

That line is executed at runtime, meaning that, if the type "animalType" is actually not an extension of the class "Animal", this line will fail at runtime. Also, one of the constructors of your type "animalType" needs to receive exactly one argument of whatever type "RandomName()" function returns, otherwise you will also have a runtime error.

EDIT: Reflection has a performance cost and should be avoided when possible. KMoussa suggested a good approach you can follow that avoids reflection and thus is much better than the reflection approach.

MattD
  • 4,220
  • 2
  • 34
  • 44
Ricardo Alves
  • 1,071
  • 18
  • 36
0

You could use reflection OR you could keep some type safety and use something called the 'Curiously recurring template pattern'. It uses generics, if you aren't familiar with that concept, I would do some reading up as they are very powerful, useful and prevalent in the .Net Eco system. Any way, here is what I would do

public abstract class Animal<T> 
    where T : Animal<T>
{
    public string Name {get; private set;}
    public Animal(string name)
    {
        Name = name;
    }

    public abstract T Reproduce();  

    public static T Reproduce(T animalToReproduce)
    {
        return animalToReproduce.Reproduce();
    }

}

public class Lion : Animal<Lion>
{
    public Lion(string name)
        : base (name)
    {

    }
    public override Lion Reproduce()
    {
        return new Lion(RandomName());
    }

}

Then you can just call Animal.Reproduce(yourAnimalInstance) this will return an object of the correct type. For example

Lion myLion = GetALionFromSomewhere();
Lion babyLion = Animal.Reproduce(myLion);

That will compile and you've got all the goodness of type safety

Dave
  • 2,829
  • 3
  • 17
  • 44