Covariance and contravariance in C#.

  • Contra-variant Meaning that the generic type parameter can change from a class to a class derived from it. In C#, you indicate contra-variant generic type parameters with the in keyword. Contra-variant generic type parameters can appear only in input positions such as a method’s argument.
  • Covariant Meaning that the generic type argument can change from a class to one of its base classes. In C#, you indicate covariant generic type parameters with the out keyword. Covariant generic type parameters can appear only in output positions such as a method’s return type.

Variance applies only if the compiler can verify that a reference conversion exists between types. In other words, variance is not possible for value types because boxing would be required.

Let’s say you have a class Person and a class that derives from it, Teacher. You have some operations that take an IEnumerable<Person> as the argument. In your School class you have a method that returns an IEnumerable<Teacher>. Covariance allows you to directly use that result for the methods that take an IEnumerable<Person>.

public class Person { } 

public class Teacher : Person { } 

public class MailingList
{
    public void Add( IEnumerable<Person> people ) { ... }
}

public class School
{
    public IEnumerable<Teacher> GetTeachers() { ... }
}

 ...

var teachers = school.GetTeachers();
var mailingList = new MailingList();
mailingList.Add(teachers);

Contravariance example:

// Contravariance.           
// Assume that I have this method: 
// static void SetObject(object o) { } 
Action<object> actObject = SetObject;
// 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<string> actString = actObject;

In addition lets see what Jeffrey Richter talks about this topic from CLR via C# book:

public delegate TResult Func<in T, out TResult>(T arg);

Here, the generic type parameter T is marked with the in keyword, making it contra-variant; and the generic type parameter TResult is marked with the out keyword, making it covariant.

When using delegates that take generic arguments and return types, it is recommended to always specify the in and out keywords for contra-variance and covariance whenever possible, because doing this has no ill effects and enables your delegate to be used in more scenarios.

Share this post:Tweet about this on TwitterShare on Facebook0Share on LinkedIn0Share on Google+0Share on Reddit0Email this to someoneDigg this