0

I have base class Animal, and I created many classes which inherits from it, such as Dog, Cat, Monkey ... now I want to implement the feature that based on user input, create the object based on the input so that I can run the override version functions inside them. Something like that:

//Animal.cs
abstract class Animal
{
    protected abstract void Func()
}

//Dog(or other animal).cs
class Dog:Animal
{
    protected override void Func() {Do something;}
}

//program.cs
public static void main()
{
    Animal a = null;
    string str = Console.ReadLine();
    a = "new str()"; // should have some try-catch module, omit here       
}

I have hundreds of animals, so using if or switch does not look a good solution; any good methods?

Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171
a4194304
  • 366
  • 2
  • 13
  • 3
    Possible duplicate of [Create an instance of a class from a string](https://stackoverflow.com/questions/223952/create-an-instance-of-a-class-from-a-string) – Yeldar Kurmangaliyev Sep 28 '18 at 10:00
  • Create a string[](or an enum) of possible inputs, let the user know if he didn't type one that is in this list. If he selected an available use a `switch` to create the right animal. Reflection is a bad approach imo – Tim Schmelter Sep 28 '18 at 10:03
  • @TimSchmelter op was looking for options besides `switch` and `if`. Reflection is one of them but also a debatable topic on its own. – cl0ud Sep 28 '18 at 10:19
  • @cl0ud: what other option than reflection you have? – Tim Schmelter Sep 28 '18 at 10:23

1 Answers1

4

One way do this would be to use a factory using reflection at runtime. Its not the neatest but will avoid you having to use if statements.

 public static class AnimalFactory
{
    public static Animal Create(string animalName)
    {
        var type = Type.GetType(typeof(Animal).Namespace + "." + animalName, throwOnError: false);

        if (type == null)
        {
            throw new InvalidOperationException(animalName.ToString() + " is not a known Animal type");
        }

        if (!typeof(Animal).IsAssignableFrom(type))
        {
            throw new InvalidOperationException(type.Name + " does not inherit from Animal");
        }

        return (Animal)Activator.CreateInstance(type);
    }
}

Based upon your namespace it will create an instance of an animal using reflection. You can pass in the animal name from your user input.

Then call it using

var type = AnimalFactory.Create("dog");
cl0ud
  • 1,524
  • 11
  • 27
  • I would include a singleton cache also since reflection is an expensive operation. If the number calls run into the thousands performance will degrade without lookups. This code requires that the "animalName" value is consistent, so building up a ConcurrentDictionary would enhance long term performance significantly. – helloserve Jan 10 '19 at 10:24