简体   繁体   中英

How to cast a list of concrete classes which implement an interface

I have an interface IAnimal and two classes(Dog, Cat), which both implement the interface.

public interface IAnimal
{
    int Age { get; set; }
}

public class Dog : IAnimal
{
    public int Age { get; set; }
}

public class Cat : IAnimal
{
    public int Age { get; set; }
}

Also, I have an AnimalsManager class as shown in the code below.

public class AnimalsManager
{
    private readonly List<Dog> _dogs = new List<Dog>();
    private readonly List<Cat> _cats = new List<Cat>();

    public void SetTargetAnimalsAge(bool isDog, int age)
    {
        if (isDog)
        {
            setAnimalsAge(_dogs, age);
        }
        else
        {
            setAnimalsAge(_cats, age);
        }
    }

    private static void setAnimalsAge<T>(IEnumerable<T> animals, int age) where T : class, IAnimal
    {
        foreach (var animal in animals)
        {
            animal.Age = age;
        }
    }
}

In the method SetTargetAnimalsAge, setAnimalsAge is used twice depending on the value of isDog argument. I'd like to unite these 2 usages into 1, but the following codes do not compile.

// Do not compile.
// var animals = isDog ? _dogs : _cats;
// var animals = isDog ? _dogs as List<IAnimal> : _cats as List<IAnimal>;

setAnimalsAge(animals, age);

How is it possible to handle one of the lists of Dogs and Cats as a list of IAnimal?

Please dont make 2 separate lists, one for dog & one for cat. AnimalsManager should know only about IAnimal . Stick to Interfaces & thus Dependency inversion

public class AnimalsManager
    {
        private readonly List<IAnimal> _animals = new List<IAnimal>();

        public void SetTargetAnimalsAge(int age)
        {
            setAnimalsAge(_animals, age);
        }

        private static void setAnimalsAge<T>(IEnumerable<T> animals, int age) where T : class, IAnimal
        {
            foreach (var animal in animals)
            {
                animal.Age = age;
            }
        }
    }

You can't have it as IList<T> because IList<T> is not covariant but IEnumerable<T> is covariant. You can cast it to IEnumerable<T> and that should work.

For example, following code should work:

public void SetTargetAnimalsAge(bool isDog, int age)
{   
     var animals = isDog ? (IEnumerable<IAnimal>)_dogs : _cats;
     setAnimalsAge(animals, age);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM