3

I ran in an overloading resolution problem which I did not expect. Apparently the compiler rather resolves a call to the MyPrint method passing "Hello world" to the MyPrint<T>(T : struct) in the derived class than to the MyPrint(string) defined in the base class. And since the method that the resolver chose will not accept the string, I get a compiler error.

I suppose it has to do with the Brittle Base Class problem as Jon Skeet wrote in his book, and Eric Lippert on his blog. Lippert quotes the standard as saying:

Methods in a base class are not candidates if any method in a derived class is applicable.

But I don't see any method in the derived class being applicable, and neither does the compiler judging from the error. I would like to know two things: why does it work this way, and how can I let C# do what I want it to do again?

Contrived example demonstrating the problem:

class Program
{
    static void Main(string[] args)
    {
        Derived d = new Derived();

        d.MyPrint(10);

        // ERROR: The type 'string' must be a non-nullable value type
        // in order to use it as parameter 'T'
        // in the generic type or method 'Derived.MyPrint<T>(T)'.
        d.MyPrint("Hello world!");
    }
}

class Base
{
    // I print only strings.
    public void MyPrint(string value)
    {
        Console.WriteLine("String: " + value);
    }
}

class Derived : Base
{
    // I print any primitive type, enums and DateTime,
    // but NOT string (since that is not a value type).
    public void MyPrint<T>(T value)
        where T : struct, IConvertible
    {
        Console.WriteLine("IConvertible: " + value.ToString());
    }
}
Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
  • 2
    MyPrint looks like MyPrint during overload resolution, and then later fails because the constraints are not met. A result of "constraints are not part of the signature", I guess – harold Dec 10 '11 at 18:30
  • It would be good to put that as an answer instead than a comment – Sebastian Piu Dec 10 '11 at 19:12

2 Answers2

2

You already found half of the reason, but you also need Constraints are not part of the signature. Combined with "Methods in a base class are not candidates if any method in a derived class is applicable", you get that during overload resolution there are two methods that look like MyPrint(string) and are therefore applicable, so the one in the most-derived class is chosen. Only after that is the constraint checked, which then fails.

harold
  • 61,398
  • 6
  • 86
  • 164
0

You can make it work, if you define this in your derived class:

public new void MyPrint(string value)
{
    base.MyPrint(value);
}

As for the "why", sorry I don't know. Probably the C# Language Specification can help to answer this question.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188