Share via


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!

Comments

  • Anonymous
    March 05, 2010
    You are right that this functionality should have been included in the CLR. Anyway, better late than never eh?

  • Anonymous
    March 10, 2010
    That's interesting concept and I am pretty sure that there are situations when you may want to employ covariance in your code. That example though does not implement that interface explicitly although the code works (I have checked it in RC 2010). That leads me to believe that certain things are defaulted in the procedure of classes inheritance itself.