Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array co-variance in C# generic list

I have an example where I want an abstract class interface to return something like this

abstract class AnimalProcessor {
    public abstract IList<Animal> ProcessResults();
}

Then the concrete examples

class GiraffeProcessor : AnimalProcessor {
    public override IList<Animal> ProcessResults() {
        return new List<Giraffe>();
    }
}

class LionProcessor : AnimalProcessor {
    public override IList<Animal> ProcessResults() {
        return new List<Lion>();
    }
}

The problem is that the concrete classes need to have the same signature to override the ProcessResults() method so they need to return an IList<Animal>, however the ACTUAL data I want to return is an IList<Lion>, IList<Giraffe> etc, but then the calling code has to do

GiraffeProcessor processor = new GiraffeProcessor();
IList<Animal> results = processor.GetResults();

Which does not give me an Ilist which is what I want.

Problems

1) Above code does not compile. The giraffeProcessor has to return a concrete List<Animal>, you can populate it with Giraffe objects but the object type you construct to return has to be List<Animal>. Not ideal.

2) When you return the results, you can only get an IList<Animal>, not IList<Giraffe>. I have tried casting explicitly to IList<Giraffe> with IList<Giraffe> results = (IList<Giraffe>) processor.GetResults(); which gives a runtime error, presumably because the object returned is NOT an IList<Giraffe>, it is an IList<Animal> which CONTAINS Giraffe objects.

Can anyone suggest what I am doing wrong here with my design as Im a bit stumped as to the best way to accomplish this.

like image 248
NZJames Avatar asked Feb 21 '23 23:02

NZJames


1 Answers

How about:

abstract class AnimalProcessor<T> where T : Animal {
    public abstract IList<T> ProcessResults();
}

class GiraffeProcessor : AnimalProcessor<Giraffe> {
    public override IList<Giraffe> ProcessResults() {
        return new List<Giraffe>();
    }
}

class LionProcessor : AnimalProcessor<Lion> {
    public override IList<Lion> ProcessResults() {
        return new List<Lion>();
    }
}
like image 63
Marc Gravell Avatar answered Mar 07 '23 23:03

Marc Gravell