Sowdowdow
Sowdowdow

Reputation: 439

Instantiate a dynamic Type in C#

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());
}

Upvotes: 1

Views: 109

Answers (3)

Ricardo Alves
Ricardo Alves

Reputation: 1131

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.

Upvotes: 3

KMoussa
KMoussa

Reputation: 1578

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

Upvotes: 4

Dave
Dave

Reputation: 3017

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

Upvotes: 0

Related Questions