简体   繁体   中英

Method overload selecting generic method when I was expecting it to select non-generic method

Take the following code:

class BaseClassA { }
class DerivedClassA1 : BaseClassA { }

class BaseClassB { }
class DerivedClassB1 : BaseClassB { }

static class Operations
{
    public static BaseClassA Method(BaseClassA baseA)
    {
        //...
        return baseA;
    }

    public static TBaseClassB Method<TBaseClassB>(TBaseClassB baseB)
        where TBaseClassB : BaseClassB, new()
    {
        //...
        return baseB;
    }

    class Program
    {
        static void Main(string[] args)
        {
            BaseClassA baseA = new BaseClassA();
            DerivedClassA1 derivedA1 = new DerivedClassA1();
            DerivedClassB1 derivedB1 = new DerivedClassB1();

            baseA = Operations.Method(baseA);
            derivedA1 = Operations.Method(derivedA1); // Compilation error
            derivedB1 = Operations.Method(derivedB1);
        }
    }
}

The line marked // Compilation error results in the following error:

The type 'DerivedClassA1' cannot be used as type parameter
'TBaseClassB' in the generic type or method
'Operations.Method<TBaseClassB>(TBaseClassB)'.
There is no implicit reference conversion from 'DerivedClassA1'
to 'BaseClassB'.

It appears that method overloading is selecting the Operations.Method<TBaseClassB>(TBaseClassB) method overload as opposed to the Operations.Method(BaseClassA) when given an argument of type DerivedClassA1 , which is contrary to what I would expect. Why is this? Am I doing something wrong? Is there a alternative/correct way of achieving what I want, which is to call the Method(BaseClassA) method overload.

Note that the example code is a simplified equivalent of some real code I'm working on. Apologies if the example looks contrived.

Overload resolution doesn't take generic constraints into account, because these constraints are not really part of the method signature (you can't create identical methods in the same class where only the generic constraints are different). The resolution algorithm first selects the best candidate, and only then checks if it verifies the constraints.

In your case, if you ignore the where TBaseClassB : BaseClassB, new() constraint, the generic overload is a better candidate, because if TBaseClassB is DerivedClassA1 , it is a closer match than the non generic one ( Method(DerivedClassA1) is closer than Method(BaseClassA) ). But then, it checks the constraint and sees that DerivedClassA1 doesn't inherit BaseClassB , which causes the error.

In other words, the non-generic overload has already been eliminated before the generic constraint is checked.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM