How to cast a list or array to a subtype in C#?

Viewed 189

I have a class with a member for a list of objects. Lets say i have an Animal base class and subtypes of Cat and Dog. The list will always contain only Dogs or only Cats but i do not know up front.

class MyClass {

    public readonly List<Animal> Data = new();

    public void MethodForDogs()
    {
        Data.Add(new Dog());
    }

    public void MethodForCats()
    {
        Data.Add(new Cat());
    }

    public void DoSomething()
    {
        HelperClass.DoIt(Data);
    }
}

class HelperClass {

    public static void DoIt(List<Animals> data) {

        if (data[0].GetType() == typeof(Cat) ) {
            var arrayCats = new Cat[data.Count];
            int i = 0;
            foreach (Animal item in data) {
                arrayCats[i++] = (Cat) item;
            }
            // use arrayCats
            ..
        }
        else if (data[0].GetType() == typeof(Dog) {
           // same, then use arrayDogs
           ..
        }
    }
}

what did NOT work was a direct cast, like

var arrayCats = (Cat[])data.ToArray();

even though i can check that all members are Cats. Is there a more elegant way to do this?

1 Answers

You can do it the following way:

class HelperClass
{
    public static void DoIt(List<Animals> data)
    {
         if(data.All(a => a is Dog))
         {
              Dog[] dogs = data.OfType<Dog>().ToArray();
              // do something with dogs
         }
         else if(data.All(a => a is Cat))
         {
              Cat[] cats= data.OfType<Cat>().ToArray();
              // do something with cats
         }
         else
         {
            throw new ArgumentException("data must contain items of the same type");
         }
     }
}

With All, you check whether all items of your list fulfill a condition (in your case the type). OfType() gets you all items which have a certain type (in your case: all items) automatically casted to that type. If the list is of mixed type, the method will throw an exception (of course, you can use another error handling that fits more to your needs).

But you should also consider @AlphaDelta's comment. To me, it seems a bit strange that you have this list containg only one subtype.

Related