Question

Okay, I've been instructed that due to contravariance the compiler should be able to infer that T=Circle and therefore allow compilation. However, with compiler version 4.0.30319.1 I get the following error:

error CS0311: The type 'Testable.Shape' cannot be used as type parameter 'T' in the generic type or method 'Testable.Test.Foo(System.IComparable, T)'. There is no implicit reference conversion from 'Testable.Shape' to 'Testable.ICircle'.

The code, however, compiles normally if I implement IComparable on the Circle class. What might be the problem here?

using System; 

namespace Testable 
{ 
    public class Test 
    { 
        public static void Main() 
        { 
            Foo(new Circle(), new Circle()); 
        } 

        public static void Foo<T>(IComparable<T> a, T b) where T : ICircle 
        { 
            a.CompareTo(b); 
        } 
    } 

    public interface ICircle 
    { 
    } 

    public class Shape : IComparable<Shape>
    { 
        public Int32 CompareTo(Shape other) 
        { 
            Console.WriteLine("Called CompareTo(Shape)"); 
            return 0; 
        } 
    } 

    public class Circle : Shape, ICircle 
    { 
    } 
}
Was it helpful?

Solution

The problem is that Circle implements IComparable<Shape>, and so the compiler chooses Shape for T. However, Shape does not implement ICircle, and so you get the error you see.

I suppose that begs the question, though. Why doesn't the compiler revise its guess to Circle once it sees the ICircle constraint. The answer is that constraints are not used to aid in type inference. They can only invalidate a guess after it has been made.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top