C# variance : The Co and Contra variance explained

by silvercrux @ 9. August 2010 23:07

This topic can be ideally explained with a simple and pragmatic 2 part Q and A.

What is Covariance and Contra variance in C# 4 ?

This can be best explained by an example. If you image there are 2 types : x and y, then exactly one of the statement is true :

1) x < y
2) x > y
3) x = y
4) x not related to y (Both are totally different having their own chain)

Memory locations in C# all have a type associated with them. At runtime you can store an object which is an instance of an equal or smaller type in that memory location.

So considering that :
Covariant : Is converting from narrower to a wider type
contra variant : Is Conversion from wider to a narrower type

Covariance basically means that the return value of a method that is referenced by your delegate can have a different return type than that specified by the delegate itself, so long as the return type of the method is a subclass of the return type of the delegate. Basically this means from going to a wider type from a narrower type.

 

Why do you care about Co and Contra variance ?

Prior to C# 4.0, language was not capable of working with co and contra variance conversion. Now it does support. So the question is why you might need them ? Well the answer is simple, now Inheritance hierarchy works across Generic types, thanks to Covariance and Contra variance support in C# 4.0.

Let's take an example (This would not work in versions prior to C# 4.0) :

Covariant

   1: class Fruit { }
   2:     class Apple : Fruit { } 
   3:  
   4:     class Program
   5:     {
   6:         delegate T MyFunc<out T>();
   7:         static void Main(string[] args)
   8:         {
   9:              MyFunc<Apple> apple1 = () => new Apple();
  10:              MyFunc<Fruit> fruit = apple1;
  11:         }
  12:     } 
  13:  

In the above code we are assigning a narrower type to a wider type. Notice the use of the word "out" in Delegate MyFunc definition

Contravariant

   1: class Fruit { }
   2:     class Apple : Fruit { } 
   3:  
   4:     class Program
   5:     {
   6:         delegate void MyAction<in T>(T a);
   7:         static void Main(string[] args)
   8:         {
   9:              MyFunc<Fruit> fruit = () => new Fruit();
  10:              MyFunc<Apple> apple1 = fruit;
  11:         }
  12:     }

In the above code we are assigning a narrower type to a wider type. Notice the use of the word "in" in Delegate MyFunc definition

I hope this clears the confusion about Co and Contra-variance. If it's still not clear we can talk via comments :)





C# 4.0 Named Parameters Explained

by silvercrux @ 9. August 2010 22:18

Prior to C# 4.0, we have to remember (though intellisense helped!) the order of each argument to use it in the consuming code.

C# 4.0 introduces a new concept which frees you to provide value to arguments in a specified order. For example, a function that calculates dearness allowance for an employee can be called in the standard way by sending arguments for salary and inflation percentage by position, in the order defined by the function.

   1: GetDearnessAllowance(5000, 9);


If you do not remember the order of the parameters but you do know their names, you can send the arguments in either order, weight first or height first.

   1: GetDearnessAllowance(wage: 5000, inflation: 9);

 

OR

   1: GetDearnessAllowance(inflation: 9, wage: 5000);

Named arguments also improve the readability of your code by identifying what each argument represents.

A named argument can follow positional arguments, as shown here.

   1: GetDearnessAllowance(5000, inflation: 9);

However, a positional argument cannot follow a named argument. The following statement causes a compiler error.

   1: //GetDearnessAllowance(weight: 5000, 9);

 

We hope this clears up the matter.





© Copyright SilverCrux Technologies. All rights reserved. We provide website html services.