pashov.net/code|January 20, 2015

Daily Archives: January 20, 2015

.NET

Variance and Contravariance in C# generics

Published by:

No, it is not a mistake – you didn’t landed on a math blog although the terms in the title sound more math than IT. However, variance and contravariance are terms deeply rooted in C# since version 4.

The simplest way to think about those is that variance preserves the direction (from less derived object to more derived on – i.e. object->string) while contravariance reverses it. Variance is somewhat intuitive as it coincides with assignment compatibility. It is natural to make something as Object a = “test string”.

If you examine IEnumerable interface in the .net dlls, you will find out that it’s signature is IEnumerable (we denote variant generics with out and contravariant with in) and it means that the interface works with generic types that behave variant. So that if we have SomeMethod(IEnumerable items) we can pass it parameter as IEnumerable items and that’s very logical because if we can enumerate and manipulate the less derived type it is safe to go through and manipulate the more derived type.

I personally find contravariance way more challenging. I wont try to explain it but rather show an example which is very self-explanatory:

 public class Animal
    {
        public void SayYourType()
        {
            Console.WriteLine(this.GetType().Name);
        }
    }


    public class Human : Animal
    {

    }

So far so good – we have a class Human to derive from Animal. They do nothing more than say their types so that we can keep things simple

    public interface ICallType<in T>
    {
        void CallType(T x);
    }

    public class AnimalTypeCaller : ICallType<Animal>
    {
        public void CallType(Animal x)
        {
            x.SayYourType();
        }
    }

    public class TypeDiscoverer<T>
    {
        T Item;
        ICallType<T> TypeCaller;

        public TypeDiscoverer(T item, ICallType<T> typeCaller)
        {
            Item = item;
            TypeCaller = typeCaller;
        }

        public void DiscoverType()
        {
            TypeCaller.CallType(Item);
        }
    }

lets have an interface that works with generics and exposes only one method that is able to call the type (Note the in keyword). Let’s also have a concrete implementation – the AnimalTypeCaller that inherits from ICallType and works with objects of type Animal. Finally we have a class that works with generics, takes a generic item argument and ICallType interface and is able to call the type of the underlying item using concrete implementation of the interface ICallType.

The magic lies in the next two lines though:

var humanTypeDiscoverer = new TypeDiscoverer<Human>(human,new AnimalTypeCaller());
humanTypeDiscoverer.DiscoverType();

we declare humanTypeDiscoverer that works with Human object but pass it AnimalTypeCaller, so we reverse the direction- > we handle more derived types(Human) with handler that works with less derived types (Animal). Even the intellisense will hint you that it expects ICallType of type Human but because of the contravariance and the in keyword, the above code is perfectly legal and works as expected and we can treat Humans with AnimalTypeCaller 🙂

This pattern is used with handlers and most notably comparers. IComparer is implemented this way. And if you think about it, it makes sense – it is ok to compare integers with an object comparer, but comparing objects with int comparer would be strange.

I suggest you to make yourself a little proof of concept if you still have difficulty to grasp the idea. I spent a lot of time reading on the topic but it took me only 15 minutes to make my own example. 10 lines of code say much more than pages of text. And are more interesting to read 🙂