Limitation of generics in C#2

I'm currently reading Jon skeet's amazing book "C# in depth (3d version)". I'm stuck on p.99 dealing with lack of contravariance for generics.

class TestGenericVariance
{
    public static void Main(string[] args)
    {
        IComparer<IShape> x =new AreaComparer();
        List<Circle> circles = new List<Circle>();
        circles.Add(new Circle());
        circles.Add(new Circle());
        //The following line is invalid, Sort expects IComparer<Circle>
        circles.Sort(x);
    }

    public interface IShape
    {

    }

    public class Circle : IShape
    {

    }

    public class AreaComparer : IComparer<IShape>
    {
        public int Compare(IShape x, IShape y)
        {
            //No matter, just for the test
            return 0;
        }
    }   
}

This code is not working because Sort method expects

    IComparer<Circle>

as parameter type.

One of the work around suggested p.99 is to make AreaComparer class generic :

    class AreaComparer<T> : IComparer<T> where T : IShape

And then modify non-generic AreaComparer to derive from the generic one :

    class AreaComparer : AreaComparer<IShape>

In C#2, the code doesn't compile because Sort method on circles is still expecting an

    IComparer<Circle>

Am I missing something ?

Nota :If I change to :

    class AreaComparer : AreaComparer<Circle>

The first line of code in the main method asks form an explicit conversion

Thank you all for your help.

Jon Skeet
people
quotationmark

The idea is that you make AreaComparer generic like this:

public class AreaComparer<T> : IComparer<T> where T : IShape
{
    public int Compare(T x, T y)
    {
        return x.Area.CompareTo(y.Area);
    }
}

Then when you need to sort, you construct a comparer with the correct type argument:

circles.Sort(new AreaComparer<Circle>());

Note that this is assuming that IShape has an Area property (as stated at the bottom of p97). That isn't in your sample code, and is required in order to implement the comparer sensibly.

The part about the non-generic derived class was only to simplify cases where you're happy with using IShape and don't want to keep repeating that.

people

See more on this question at Stackoverflow