New Features of C# 4.0: Variance

New Features of C# 4.0: Variance


The last feature left out in parent blog article New Features of C# is variance and this article aims at concluding the detail study of new features of C# 4.0 we listed in that with the discussion of variance in C# 4.0. (We have detailed about Dynamic Lookup and Optional and Named parameters in our previous blog posts).

Before discussing the concept of variance in C# 4.0, let us consider a scenario wherein we are having a strongly typed list that is assigned to hold a list of plain C# objects. To the list, we would like to populate a list of integers from another list thinking that since it could be converted to object. But C# generics will not allow this and throw an exception. The above is what we term as variance. We can overcome this in two ways.

  1. We can create a helper method that accepts the integer parameters, converts them to objects, and put them into the list. This methodology works if we just want to populate the list as mentioned above.
  2. Suppose we need an IEnumerable type of integer objects to be passed into a method that takes an IEnumerable type of plain objects, then we need to create a wrapper object that does the conversion of each member of the interface.

But still the above ways do not provide a better solution in case of complex scenarios wherein both read and write operations involve in the List. In such cases, we can write wrapper for read operations but writing the same for write operations may end up in failure because in case a string type is allowed to be accommodated into a list of objects and if we pass some other type object into it during runtime, it may cause failure.

That being said, C# 4.0 has evolved with a new feature – support for variance. C# 4.0 variance has two important characteristics in it.

  1. C# 4.0 variance will be supported only for interfaces and delegates.
  2. We have to decorate the type of the parameter as in or out.

Specifying out parameter only implies that the delegate or interface does not allow any insertion of types other than specified but can return the types other than specified. Thus, an IEnumerable type parameter containing list of objects for a method can return the IEnumerable type object containing string if the out parameter is specified so. This type of variance is called covariance. In case of covariance direction of assignment compatibility is preserved only in forward direction, i.e., a string can be accommodated into an object.

Then what about contravariance? Contravariance is the reverse of covariance in which the direction of assignment compatibility is preserved in reverse direction also.

Let us provide a scenario-based example for Covariance & Contravariance. Consider the following sets – {Horse, Cat, Animal, Grape, Apple, Fruit} and if we relate them as IEnumerable<Horse>, IEnumerable<Cat>, IEnumerable<Animal>, IEnumerable<Apple>, IEnumerable<Fruit>, then it means that Horse and Cat can be accommodated into Animal list similarly Apple and Grape can be accommodated into Fruit but the reverse is not possible as we cannot accommodate Animal objects into Horse even though Horse is an animal. If we want to create an IEnumerable that could take Animal objects into Horse collection, we need to specify them as a contravariant list using in parameter.

In short, covariance and contravariance provides us with a facility to pass inappropriate types into C# delegates and interfaces whenever it is safe to do by way of defining them as in and out parameters.

, , , , ,

Open chat
Can I help you?