This article explains the following points:
- Introduction
- Definition
- Issue before these two
- Array Covariance
- Delegate Covariance
- Variance in Generic Type Parameters
- Conclusion
Introduction
In this entire article we will learn all about Covariance and Contravariance, including what the issues were with development before these two.
Definition
These two, Covariance and Contravariance, wre introduced in C# 4.0. As per MSDN we simply define them as:
"covariance and contravariance enable implicit reference conversion for array types, delegate types and generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it."
In simple words, we can say Covariance and Contravariance are the polymorphism extensions to array types, delegate types and generic types (we will see in future sections).
Issue before these two
What were the issues before the invension of these two? Let's consider the following example:
- class GrandFather
- {
- }
- class Son : GrandFather
- {
- }
- class GrandSon : GrandFather
- {
- }
- 1. GrandFather father = new Son();
- 2. father = new GrandSon();
- //will throw exception prior to version 4.0
- IEnumerable<GrandFather> fathers = new List<Son>();
Now, try this in C# 4.0:
- //will work fine with version 4.0
- IEnumerable<GrandFather> fathers = new List<Son>();
Consider the following method is in the class:
- static void ParentalObject(object o)
- {
- //method signature
- }
- Action<Object> actionObj = ParentalObject;
- Action<Object> actionObj1 = actionObj;
Array Covariance
This is nothing but an implicit conversion of an array of a more derived type to an array of a less derived type. Unfortunately this is not type-safe.
- object[] strArray = new string[10];
- strArray[0] = 1; //will throw runtime exception
Delegate Covariance
This type of Covariance is also called method group variance. From MSDN you can assign to delegates not only methods that have matching signatures, but also methods that return more derived types (covariance) or that accept parameters that have less derived types (contravariance) than that specified by the delegate type. This includes both generic and non-generic delegates.
- static string Parental()
- {
- return "Grandfather name is: Lala Bhagwan Das";
- }
- Func<object> parentalLambda = () => Parental(); //lambda expression
- Func<object> parentalFunc = Parental; //Grouped
- static string ParentalObject(object obj)
- {
- //method signature
- }
A delegate specifies a parameter type as a string but can assign a method that takes an object.
- Action<String> parentalDel = ParentalObject;
As per MSDN you can enable implicit conversion between delegates, so that generic delegates that have different types specified by generic type parameters can be assigned to each other, if the types are inherited from each other as required by variance.
To enable implicit conversion, you must explicitly declare generic parameters in a delegate as covariant or contravariant using the in or out keyword.
Consider the following code:
- delegate T ParentalGenericDelegate<out T>();
- ParentalGenericDelegate<string> grandFatherName = () => "Grandfather name is: Lala Bhagwan Das";
- ParentalGenericDelegate<object> anotherGenericDelegate = () => grandFatherName;
Conclusion
We can say Covariance and Contravariance are the polymorphism extensions to array types, delegate types and generic types (we will see in future sections).

Gaurav Kumar AroraPosted Jan 16, 2015, 5:39 AM
thanks Vithal ji
Vithal WadjePosted Dec 14, 2014, 1:34 PM
another super article thanks for sharing
Gaurav Kumar AroraPosted Dec 14, 2014, 12:29 PM
Jitendra Kumar - Thanks
Jitendra KumarPosted Dec 14, 2014, 12:26 PM
Good..