Generic Co- and Contravariance in Visual Basic 2010

In this month’s issue of MSDN Magazine we’ve got an article on a new language/.NET 4 feature called Generic Co- and Contravariance by Binyam Kelile:

MSDN Magazine: Generic Co- and Contravariance in Visual Basic 2010

I have to admit if I think about this feature too hard my head starts spinning in circles faster than Linda Blair in the Exorcist. But in actuality it’s one of those features that “just works” and probably should have already been available in the CLR. The easiest way for me to think about it is that it enables true inheritance scenarios with generics.

Consider this practical example. Say I have a class called Student that inherits from Person:

 Public Class Person
    Property Name As String
    Property Age As Integer
End Class

Public Class Student
    Inherits Person

    Public Property Score As Decimal
End Class

Now say I have a generic List(Of Student) that I want to pass to a method that accepts an IEnumerable(Of Person)):

 Sub Main()
    Dim students As New List(Of Student) From
        {New Student With {.Name = "Beth", .Age = 10, .Score = 90.5},
         New Student With {.Name = "Alan", .Age = 11, .Score = 100},
         New Student With {.Name = "Jenn", .Age = 12, .Score = 98.5}}


    PrintNames(students) 'This will not work in VS2008
End Sub

Sub PrintNames(ByVal list As IEnumerable(Of Person))
    For Each p In list
        Console.WriteLine(p.Name)
    Next
End Sub

Even though a List implements IEnumerable and a Student inherits from Person this will not work in Visual Studio 2008 because generic types behave invariantly in the CLR previous to version 4.0. This is now supported. In Visual Basic 10 (and C# 4) you now have the ability to declare covariant (widening)and contravariant (narrowing)generic types with the Out and In modifiers. So they changed the IEnumerable interface in the CLR 4.0 to designate a covariant generic type:

 Public Interface IEnumerable(Of Out T) ...

So this means that the method call above will work now because a widening conversion is allowed. Contravariance is the exact opposite. With the In modifier on the generic type a narrowing conversion is allowed. Piece of cake, right?

Check out the Generic Co- and Contravariance article for a deep dive into this feature and how to use it in your programs. Also check out Lucian’s post: Co- and contra-variance: how do I convert a List(Of Apple) into a List(Of Fruit)?

Enjoy!