kateroh
kateroh

Reputation: 4416

Need to abstract collections of objects (C#)

In the following simplified example, I need to abstract Collection classes in such a way that PrintFruitsAndEaters(oranges, orangeEaters); or PrintFruitsAndEaters(apples, appleEaters); becomes possible:

abstract class Fruit
abstract class FruitEater

class Apple : Fruit
class AppleEater : FruitEater
class Orange : Fruit
class OrangeEater : FruitEater

class AppleCollection : List<Apple>
class OrangeCollection : List<Orange>
class AppleEaterCollection : List<AppleEater>
class OrangeEaterCollection : List<OrangeEater>

I've tried templatizing the method and collection classes, but i need to access methods specific to Fruit and FruitEater classes:

class FruitCollection<T> : List<T>
class FruitEaterCollection<T> : List<T>

void PrintFruitsAndEaters<T, S>(FruitCollection<T> fruits, FruitEaterCollection<S> eaters)

Upvotes: 1

Views: 314

Answers (1)

cdhowie
cdhowie

Reputation: 169143

Then you want this:

void PrintFruitsAndEaters<T, S>(
    FruitCollection<T> fruits,
    FruitEaterCollection<S> eaters)
        where T : Fruit
        where S : FruitEater
{
    // ...
}

This will constrain the T and S types as you require; calling the method with a FruitCollection<T>, where the T cannot be guaranteed to be Fruit or a subtype, will result in a compile-time error. Same with S and FruitEater.

Because of the constraint, when working with a value of type T you will be able to access members of the Fruit class, and when working with a value of type S you will be able to access members of the FruitEater class.

Note that, as per Brian's (deleted) answer, you might want to add constraints to the collection types too:

class FruitCollection<T> : List<T> where T : Fruit { }
class FruitEaterCollection<T> : List<T> where T : FruitEater { }

But this will still not allow you to omit the constraints on the method.

(Also, inheriting List<T> is an evil thing to do, instead use IList<T>)

Upvotes: 6

Related Questions