Covariance and Contravariance

The .NET languages support the concepts of covariance and contravariance. These concepts enable you to reduce restrictions on strong typing when working with delegates, generics, or generic collections of objects. In certain situations, decreasing the type restrictions might increase your ability to reuse code and objects and decrease the need to do a lot of casting or converting to provide the right type to a method.

Covariance is the ability to use a more derived type than that which was originally specified by an interface or function signature. For example, you could assign a list of strings to a generic list that only takes objects if that list supports covariance (because strings inherit from objects and are thus more derived). Contravariance is similar; it is the ability to use a less-derived type for a given parameter or return value. That is, you might assign an object type as the return type for a method that returns a string (provided that method supports contravariance).

It is important to note that the target type has to support covariance or contravariance. This is not a change to the entire language. Instead, it introduces a couple new keywords to allow support for these concepts when appropriate.

Variance in Generic Collections

Many of the generic interfaces in the latest version of the .NET Framework now support variance. This includes the interfaces IEnumerable<T> and IEnumerator<T> (among others) that support covariance. This means you can have support for variance inside your collections.

For example, you might have a list of Manager objects. Recall that Manager derives from Employee. Therefore, if you need to work with the Manager list as an Employee collection, you can do so using List and the IEnumerable interface. The following code shows an example.

C#

IEnumerable<Manager> managers = new List<Manager>();
IEnumerable<Employee> employees = managers;

VB

Dim managers As IEnumerable(Of Manager) = New List(Of Manager)()
Dim employees As IEnumerable(Of Employee) = managers

The preceding code compiles and executes because Manager inherits from Employee and is thus more derived. Using covariance, you can use a list of Manager objects with a list of Employee objects. For example, you might have a method that takes a list of Employee objects as a parameter. Using covariance support, you can pass the Manager list instead.

Additional Considerations

Support for variance has additional ramifications for your coding. These include the following:

Image Custom generic classes—If you create your own custom generic classes, you can declare support for variance. You do so at the interface level using the out (covariant) and in (contravariant) keywords on generic type parameters.

Image Delegate variance—Using variance, you can assign methods to delegates that return more derived types (covariance). You can also assign those methods that accept parameters that have a less derived type (contravariance).

Image Func and Action—The generic delegates Func<> and Action<> now support variance. This enables you to more easily use these delegates with other types (and thus increase the flexibility of your code).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset