#1,069 – Contravariance and Generic Interfaces
April 7, 2014 2 Comments
Generic interfaces in C# are contravariant, provided that their type parameters are constrained with the in keyword. A contravariant generic interface allows an assignment from a constructed version of the interface on a base class to a constructed version of the interface for a derived class.
For example, if BorderCollie derives from Dog and if IAddRemove<T> is contravariant, we can do the following:
IAddRemove<Dog> dogAddRemove; // Assign dogAddRemove to some class that implements IAddRemove<Dog> IAddRemove<BorderCollie> bcAddRemove = dogAddRemove;
Below is a full example of defining a contravariant interface. Note that the LineOf<T> class implements both the covariant interface IFirstAndLast<T> and the contravariant interface IAddRemove<T>.
public interface IFirstAndLast<out T> { T First(); T Last(); } public interface IAddRemove<in T> { void AddToEnd(T item); void RemoveFromFront(T item); } public class LineOf<T> : IFirstAndLast<T>, IAddRemove<T> { private Queue<T> theQueue = new Queue<T>(); public void AddToEnd(T d) { theQueue.Enqueue(d); } public void RemoveFromFront(T d) { theQueue.Dequeue(); } public T First() { return theQueue.Peek(); } public T Last() { return theQueue.Last(); } } static void Main(string[] args) { LineOf<Dog> dogs = new LineOf<Dog>(); IAddRemove<BorderCollie> bcAddRemove = dogs; bcAddRemove.AddToEnd(new BorderCollie("Kirby")); bcAddRemove.AddToEnd(new BorderCollie("Shep")); }