Contravariance and Covariance

In a recent talk on What's New in C# 2.0, I explained the concepts of covariance and contravariance.  Several people came up to me afterwards and said they absolutely got it, but wanted to find out where to find more information.

Stephen Toub has a great article in the October 2005 issue of MSDN Magazine that explains covariance and contravariance.  Make sure to pay attention to the explanation of the ArrayTypeMismatch exception and understand why this happens.  Here is the code listing that I used during the presentation while talking about covariance:

 
using System;
using System.Collections.Generic;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            foo[] myarr = new bar[5];
            for (int i = 0; i < 5; i++)
            {
                myarr[i] = new bar();
            }

            //Uncomment this to see the ArrayTypeMismatchException
            //myarr[0] = new foo();
            
            for (int i = 0; i < 5; i++)
            {
                myarr[i].OverrideMe();
            }
        }
    }


    class foo
    {
        public virtual void OverrideMe()
        {
            Console.WriteLine("From the base");
        }
    }

    class bar : foo
    {
        public override void OverrideMe()
        {
            Console.WriteLine("From the derrived type");
        }
    }
}

The reason that most developers choose arrays is because it is just too much work to define a strongly-typed collection with iterators, arrays just makes that easier.  If that is the motivation, then Generics is the way to go instead.  We are able to move the runtime exception back into a compile-time exception and guarantee the type contained in our structure.

             List<bar> myarr = new List<bar>(5);
                        
            for (int i = 0; i < 5; i++)
            {
                myarr.Add(new bar());                
            }

            for (int i = 0; i < 5; i++)
            {
                myarr[i].OverrideMe();
            }