Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a covariant extension method on a generic interface in C#?

If the title didn't make sense, here's an example:

interface IEat { void Eat; }
class Cat : IEat { void Eat { nom(); } }
class Dog : IEat { void Eat { nom(); nom();nom(); } }
class Labrador : Dog { }

I'd like to create an extension method like this:

public static void FeedAll(this IEnumerable<out IEat> hungryAnimals) {
   foreach(var animal in hungryAnimals) animal.Eat();
}

So I can do this:

listOfCats.FeedAll();
listOfLabs.FeedAll();
listOfMixedHungryAnimals.FeedAll();

Is this possible? Where did I go wrong?

The real-world application here is that "Dog" is a major base class in my application, and there are many subclasses, each of which may have ILists of things from time to time that need to have group operations performed on them. Having to cast them just to call an extension method on a List of an interface they all implement would be suboptimal.

Edit:

I goofed up the example a little. My actual code is using IList, I was hoping to have Count and index-based operations available. Based on the answers below, I guess I'll have to go another direction for the methods that require IList semantics.

like image 414
richardtallent Avatar asked Oct 21 '22 01:10

richardtallent


1 Answers

IEnumerable is already covariant, so your extension method can accept an IEnumerable<IEat> and an IEnumerable<Dog> instance will be a valid argument, making the extension method apply to variables of those types.

Had the definition of the interface not specified that the generic argument was covariant/contravariant then there would be nothing that you extension method could do to allow that argument to be covariant. If you were using, say, a List which is invariant, there is nothing your extension method can do to allow for the use of covariance.

like image 91
Servy Avatar answered Oct 23 '22 17:10

Servy