Covariance and Contravariance in C#

Once you grow in your carrier and you want to switch for whatsoever reason. Then more than designing architecture patterns, the interviewer asks more language-specific very hard questions. One specific question that we stumble upon in most of the interviews is Covariance and Contravariance in c#.

Well, to be specific it is not that hard, just understand the basic definition of both first. As per the MSDN

Covariance:

Enables you to use a more derived type than originally specified. You can assign an instance of IEnumerable to a variable of type IEnumerable.

Contravariance:

Enables you to use a more generic (less derived) type than originally specified. You can assign an instance of Action to a variable of type Action.

You will get lots of examples on the same, and one common example is of Animals and their subclasses. This is how it looks like

I have drawn a really bad diagram in a notepad. This simply signifies that animals are derived from the object and Cat/Dog are derived from Animals Class

But before going any further you first need to understand how Action works. Action methods are of void types and can be used as lambda expressions as well.

Once you understand how delegates works, then below are the examples of both:

//Covariance example
IEnumerable<Dog> _dog= new List<Dog>();  
IEnumerable<Animals> _animal= _dog;  //assigning Dog to less derived type Animals instance.

//Contravariance example
static void SetAnimal(Animals o) { } //Consider this method
Action<Animals> actAnimal = SetAnimal;  

// An object that is instantiated with a less derived type argument
// is assigned to an object instantiated with a more derived type argument.

// Assignment compatibility is reversed.
Action<Cat> actCat= actAnimal ;  

This can be a little confusing at first, but make sure you remember these two concepts:

  • Covariance is generally used for reading an object
  • Contravariance is generally used in writing an object

Covariance And Contravariance In C# & Generic Modifiers

To understand this first we need to understand what are generic modifiers. So when you say generic modifiers, you mean they can be either of In or Out types. I believe whoever is reading has an idea about generics. Just in case, generics are defined by the <T> keyword mostly and are used for extending the usability of code.

The OUT keyword is used for covariant, do not get confused by out/ref params as both are different things. The IN is used for contravariant.

Example of OUT ( covariant ) Generic Modifier

// Covariant interface.
interface ICovariant<out R> { }

// Extending covariant interface.
interface IExtCovariant<out R> : ICovariant<R> { }

// Implementing covariant interface.
class Sample<R> : ICovariant<R> { }

class Program
{
    static void Test()
    {
        ICovariant<Object> iobj = new Sample<Object>();
        ICovariant<String> istr = new Sample<String>();

        // You can assign istr to iobj because
        // the ICovariant interface is covariant.
        iobj = istr;
    }
}

Example of IN ( contravariant ) Generic Modifier

// Contravariant interface.
interface IContravariant<in A> { }

// Extending contravariant interface.
interface IExtContravariant<in A> : IContravariant<A> { }

// Implementing contravariant interface.
class Sample<A> : IContravariant<A> { }

class Program
{
    static void Test()
    {
        IContravariant<Object> iobj = new Sample<Object>();
        IContravariant<String> istr = new Sample<String>();

        // You can assign iobj to istr because
        // the IContravariant interface is contravariant.
        istr = iobj;
    }
}

Just compare the assignment of both, as you can see both the examples above.

iobj= istr;

You can assign istr to iobj because the ICovariant interface is covariant. As per definition, you are assigning more derived types than originally specified.

istr = iobj;

You can assign iobj to istr because the IContravariant interface is contravariant. It enables you to use a more generic (less derived) type than originally specified.

Feel free to comment, Happy coding.

Thought Gem

What a gem of a thought!


Leave a Comment

Your email address will not be published. Required fields are marked *