« Home | Dell 2405FPW » | VS2005 Release » | Useful Sparkle/XAML Links » | Dead Computer Talking » | Feature Estimation » | OnTime Setup Notes » | OnTime » | Computer Zen Guestmap » | Delayed RSS/feeds » | Earthcore »

Generic List Covariance

I’m currently moving an existing .NET Framework V1.1 application to V2.0 and changing the domain model to use generics for any collections and lists. A common theme that keeps popping up during the change over is the lack of generic list covariance. In the following contrived example the Person class is a specialization of the Party class. In the V1.1 application version, an IList containing solely Person instances can be passed to any method that takes an IList and treats the items in the list as Party instances. Once a changeover to use the generic collections functionality is performed, you can’t just pass an IList<Person> instance to a method that takes an IList<Party>. The compiler will only accept passing IList<Party> instances, even though a Person is a Party.

class Party {…}

class Person : Party {…}

static void Main( string [] args )
{
    IList<Person> people = new List<Person>();
    people.Add( new Person( "Fred" ) );
    people.Add( new Person( "Wilma" ) );
    people.Add( new Person( "Barney" ) );

    PrintNames( people );
}

The following definition of PrintNames causes compilation errors since passing an IList<Person> to the method isn’t supported:

static void PrintNames( IList<Party> parties )
{
    foreach ( Party party in parties )
        Console.WriteLine( party.Name );
}

The easiest approach to handle the lack of covariance tends to end up with more use of generics in the source code than I originally expected. The generic version of the method is able to take any IList<T> where T is derived from Party. The compiler makes life easier by accepting PrintNames( people ); as a program statement where PrintNames<Person>( people ); would be the more verbose equivalent. Here’s the generic version of the PrintNames method:

static void PrintNames<T>( IList<T> parties )
    where T : Party
{
    foreach ( Party party in parties )
        Console.WriteLine( party.Name );
}

It reminded me of coding in C++ with the const functionality in terms of coding change effects. The use of generics in the code starts a sort of domino effect of code changes, similar to the flow-on effect of const changes in C++ programs. The short term reason for doing the generic list changes is to be able to create class diagrams of the domain model that shows the aggregation relationships between classes. I’m looking forward to getting these generic code changes over and done with in the app and getting onto less monotonous work.
 

Links to this post

Create a Link