12,549,655 members (45,625 online)
alternative version

49.3K views
33 bookmarked
Posted

# Variance in C#.NET 4.0 Covariance and Contravariance

, 8 Jun 2010 CPOL
 Rate this:
Conceptual Understanding of Variance in C#.NET Covariance and Contravariance

## Introduction

This article is all about Contravarance and Covariance in C# .NET 4.0. After going through lots of books and online references, I am finally able to understand what goes in making of covariance and contravariance. Understanding the concept of these two keywords would be as simple as it can be but implementing it in the real world would be a pain. For a technical architect, this concept is a must and one must dive deep to understand it. This article is more towards code driven explanation rather than verbose. My intension is to help one to grasp the true concept and theory behind Covariance and Contravariance.

## Background

Most of us must be aware of the concept of 'Equivalence Relations' in Set. This is related to mathematics and one must be wondering why I'm mixing C# with maths here but trust me, we must know this to better understand variance in C#.

In the early college days, we must have came across the mathematics concept of Equivalence. If not, then we've a chance to know this here. A relation R is Equivalence if and only if R is Reflexive, Symmetric and Transitive. If one looks at the definition of Symmetric, it will help you understand `Variance in C#.`

#### Symmetric

A relation R is symmetric iff, if x is related by R to y, then y is related by R to x. For example, being a cousin of is a symmetric relation: if X is a cousin of Y, then it is a logical consequence that Y is a cousin of X. Equivalence Relation.

#### Concept Of Variance

If y is derived from X and y relates to X, then we can assign X to y. Like X=y. This is Covariance.

If Y is derived from X and y relates to X, then we can assign y to X. Like y = X. This is Contravariance.

If class A is related to B, then B is related to A.

#### Covariance

Class B: A then we can assign A = B.

Contravariance

Class B: A then we can assign B = A.

## Rules For Variance in C# 4.0

• Covariance and Contravariance are not supported for generic classes and non generic class.It is applicable only for interface and delegate types.
• C# variance rules are not applicable to value types In other words, `IMath<int> `is not covariance-Contravariance convertible to `IMath<double>`, even though int is implicitly convertible to double.
• Should follow Inheritance relationship pattern like string is an object. If object is related to string then string is related to object.

#### Example

`Class String:Object`
• Covariance =>```Object=string; ```
• Contravariance=> `string=Object;`

Covariance interface and delegate must have `'In'` keyword declaration for input parameter. Contravariance interface and delegate must have `'Out'` keyword declaration for output parameter.

• C# .NET 4.0

## Generic Interface :Covariance and Contravariance

The below code will compile in .NET 4.0 without requiring any explicit conversion or runtime failure.The below conversion is not possible in earlier versions of .NET.

Covariance: In the below interface, we've output parameter in `RecievedData()` method and hence we've written `OUT `keyword in `Interface generics.IMessageRecieved <out T>` .

`IMessageRecieved <T > objData = new DataTX <T>();`

Once we replace generic template `T `with Covariance rule, then the resultant will be:

`IMessageRecieved <Object> objData= new DataTX <String>();`

```interface IMessageRecieved <out T>
{
T RecievedData();
}            ```

We can also have something like this here:

`IFactory <Animal> factory = new AnimalFactory <Cat>();`

Contravariance: In the below interface, we've input parameter in `SendData( T data)` method and hence we've written `IN `keyword in Interface generics. `IMessageSend <in T>`:

`IMessageSend <T > objData = new DataTX <T>();`

Once we replace generic template `T `with Contravariance rule, then the resultant will be:

`IMessageSend <String> objData= new DataTX <Object>();`
```interface IMessageSend <in T>
{
void SendData(T data);
}            ```

We can also have something like this here:

`IFactory <Cat> factory = new AnimalFactory <Animal>();`

One must go through the below code for more understanding. One can download the demo code to grasp the understanding of interface variance functionality.

```interface IMessageRecieved <out T>
{
T RecievedData();
}
interface IMessageSend <in T>
{
void SendData(T data);
}

class DataTX <T> : IMessageSend <T>, IMessageRecieved<T>
{
private T m_Data;

#region IMessageSend <T> Members ( Implicit Implementation )
void IMessageSend <T>.SendData(T data)
{
this.m_Data = data;
}
#endregion

#region IMessageRecieved <T> Members ( Implicit Implementation )

public T RecievedData()
{
return m_Data;
}
#endregion

/*
//We can make below method Virtual if we've opted Explicit Implementation
public virtual void SendData(T data)
{
this.m_Data = data;
}
*/
}
```
```class Program
{
static void Main(string[] args)
{
//Covariance
//Compiles in C# .net 4.0
IMessageSend <object> objMessageSend =  new DataTX <string>();

//Contravariance
//Compiles in C# .net 4.0
IMessageSend <string> strMessageSend = new DataTX <object>();
}
}        ```

## Real Time Example: Contravariance

Interface `Icomparer<in T>` supports contravariance and this real time example will help you understand Contravariance. In the below example, we've base comparer class `Basecomparer `that has been restricted to `Employee `class only as we applied constraint clause of `Employee `class to Interface `Icomparer `for sorting operation.

Now using Contravariance, we can allow `Manager `class to perform sorting operations without its respective `BaseComparer `class being defined. We will use `basecomparer `of `Employee `to sort `Manager `list. This is possible because `Manager `class has inheritance relationship with `Employee class`.

```public class Employee
{
private string m_Name;
private int m_ID;

public Employee(string name, int id)
{
m_Name = name;
m_ID = id;
}

public string Name
{
get { return m_Name; }
set { m_Name = value; }
}

public int ID
{
get { return m_ID; }
set { m_ID = value; }
}
}

public class Manager:Employee
{
public Manager(string name, int id) : base(name, id) { }
}

public class BaseComparer <T>: IComparer<T> where T : Employee
{
public int Compare(T x, T y)
{
return (x.ID < y.ID ? 0 : 1);
}
}```
```class Program
{
static void Main(string[] args)
{
List <Manager > managerList = new List <Manager >();

//Runs as per Contravariance Rule.
BaseComparer <Employee > objComparer1 = new BaseComparer <Employee >();
managerList.Sort(objComparer1);

List <Employee > employeeList = new List <Employee >();

//This will throw compile time ERROR ..
BaseComparer <Manager > objComparer2 = new BaseComparer <Manager >();
employeeList.Sort(objComparer2);

managerList.ForEach(e => Console.WriteLine(e.ID+ " " + e.Name));
}
}
```

If one looks at the above code, we have `IComparer <in T > `as per Contravariance,we can assign Superclass `Employee` to Subclass Manager `[ Manger=Employee]`.

```BaseComparer <Employee > objComparer1 = new BaseComparer <Employee>();
managerList.Sort(objComparer1);```

Contravariance:

`IComparer <Manager >.Sort (Employee) `

But this reverse is invalid:

`IComparer <Employee >.Sort (Manager) `

## Generic Delegate :Covariance and Contravariance

The below code is referenced from 'Charlie Calvert's Community' Blog. The below code is self explanatory. I made a few modifications in terms of replacing Lamda expression with delegate full modifier declaration of readers better understanding.

```namespace MainPKG
{
class Animal { }
class Cat : Animal { }

delegate T Func1 <out T >();
delegate void Action1   <in T >(T a);

class Program
{
public static Cat CreateCatInstance()
{
return new Cat();
}

public static void DisplayCatInstance(Animal animal)
{
Console.WriteLine(animal);
}

static void Main(string[] args)
{
// Covariance
Func1 <Cat> cat= new Func1<Cat>(CreateCatInstance);
Cat objCat = cat();
Console.WriteLine("Co:" + objCat);

Func1 <Animal> animal= delegateFunc1Cat;
Animal objAnimal = animal();
Console.WriteLine("Co:" + objAnimal);

// Contravariance
Action1 <Animal> act1 = new Action1<Animal>(DisplayCatInstance);
act1 (new Animal());
Action1 <Cat> cat1 = act1 ;
cat1 (new Cat());
}
}
}
```

We can have lambda expression for the above delegate declaration to make it short. The lambda code is being referenced from Charlie's blog.

```namespace MainPKG
{
class Animal { }
class Cat : Animal { }

delegate T Func1 <out T >();
delegate void Action1   <in T >(T a);

class Program
{
public static Cat CreateCatInstance()
{
return new Cat();
}

public static void DisplayCatInstance(Animal animal)
{
Console.WriteLine(animal);
}

static void Main(string[] args)
{
// Covariance
Func1 <Cat> cat = () => new Cat();
Func1 <Animal> animal = cat;

// Contravariance
Action1 <Animal> act1 = (ani) => { Console.WriteLine(ani); };
Action1 <Cat> cat1 = act1;
}
}
}```

If we look at the above example, what we observed is that in `Covariance `subclass `Cat `is assigned to `Superclass Animal`, i.e., for `class Cat : Animal`.

`objAnimal =objCat `

Whereas Contravariance is the opposite of Covariance, in this we can assign Superclass to subclass.

`objCat =objAnimal `

The C# variance concept is easy to understand when it comes to delegate development, but it is difficult to understand in terms of interface implementation.

## Conclusion

I hope that I was able to meet some of your expectations, to help you understand the concept of C# variance. Any suggestions or corrections are most welcome.

## History

• 8th June, 2010: Initial post

## Share

Whatsup-->Exploring--> MVC/HTML5/Javascript & Virtualization.......!
www.santoshpoojari.blogspot.com

## You may also be interested in...

 Pro Pro

 First Prev Next
 good explanation indrajeet_pat12318-Feb-14 23:03 indrajeet_pat123 18-Feb-14 23:03
 Code having typo error Member 103861947-Nov-13 0:50 Member 10386194 7-Nov-13 0:50
 there is a slight error at the start of the tutorial yaliyali1-Dec-12 23:33 yaliyali 1-Dec-12 23:33
 Typo or Error? sobo12317-Dec-11 15:28 sobo123 17-Dec-11 15:28
 My vote of 5 Dukhabanndhu Sahoo27-Oct-11 17:59 Dukhabanndhu Sahoo 27-Oct-11 17:59
 Last Visit: 31-Dec-99 18:00     Last Update: 22-Oct-16 19:54 Refresh 1