Reputation: 85
Info: IDogShelter and ICatShelter both inherit from IAnimalShelter.
Next, I have Cat and Dog classes which both implement and extend IAnimal.
IAnimalShelter has a List<IAnimal> called Animals.
ICatShelter has a List<Cat> called Animals.
IDogShelter has a List<Dog> called Animals.
Problem: ICatShelter can't have a List called Animals because IAnimalShelter has it defined as a List of IAnimal. VS says to use the "new" keyword. And so I just take it away instead and don't have a List of IAnimal on the IAnimalShelter.
And so - I have a method called GetAnimalShelters() which returns List of IAnimalShelter. I want then to be able to iterate through each IAnimal in the shelter, but can't because IAnimalShelter doesn't have a List of IAnimal. This leaves me having to cast my results into ICatShelter or IDogShelter in order to iterate through, but I'd like to be able to successfully add List of IAnimal to the IAnimalShelter instead. How can I do this?
For example:
public interface IAnimalShelter
{
List<IAnimal> Animals { get; set; }
}
public interface ICatShelter
{
List<Cat> Animals { get; set; }
}
public interface IDogShelter
{
List<Dog> Animals { get; set; }
}
And then:
List<IAnimalShelter> shelters = GetShelters(search); //Works
foreach (IAnimalShelter shelter in shelters)
{
var x = shelter.Animals;
}
So above, I want to just access the common parts of an animal, I want IAnimalShelter to have an Animals property, but for the derived shelter types to have more strongly typed Animals list.
Upvotes: 2
Views: 62
Reputation: 267
Use generics:
public interface IAnimalShelter<T> where T : IAnimal
{
List<T> Animals { get; set; }
}
public class Cat: IAnimal
{
}
public interface ICatShelter : IAnimalShelter<Cat>
{
}
public class CatShelter: ICatShelter
{
public List<Cat> Animals { get; set; }
}
Didnt test it but this should do the trick, if your ICatShelter doesnt add anything to IAnimalShelter you can even drop it and derive CatShelter directly from IAnimalShelter
Upvotes: 0
Reputation: 13837
This is called Generics. The following definitions should give you what you're looking for:
public interface IAnimal { }
public class Cat : IAnimal { }
public class Dog : IAnimal { }
public interface IAnimalShelter<T> where T : IAnimal
{
List<T> Animals { get; set; }
}
public interface ICatShelter : IAnimalShelter<Cat> { }
public interface IDogShelter : IAnimalShelter<Dog> { }
The Animals
property of an ICatShelter
will be List<Cat>
.
Implement the class like this and the compiler is happy:
public class CatShelter : ICatShelter
{
public List<Cat> Animals { get; set; }
}
Upvotes: 0
Reputation: 81143
Your type IAnimalShelter
is promising that its Animals
property will yield an object whose Add
method will accept a parameter of type Animal
. If ICatShelter
derives from IAnimalShelter
, it must also have an Animals
property that yields an object whose Add
method will accept a parameter of type Animal
.
To make this model work, you should define IShelter<out T> where T:Animal
which includes an Animals
property of type IReadOnlyList<T>
, and a TryDonate(Animal it)
method which will request that the shelter take in a particular animal. A CatShelter : IShelter<Cat>
will be able to let client code receive a readable list of objects that are guaranteed to all be of type Cat
, and clients may attempt to submit any kind of animal to it, though donations of types other than Cat
will not get added to the list.
Upvotes: 1