C # General overloaded dispatch method ambiguous

I just got into a situation where the method sending was ambiguous and was wondering if anyone could explain on what basis the compiler (.NET 4.0.30319) chooses which overload to call

interface IfaceA { } interface IfaceB<T> { void Add(IfaceA a); T Add(T t); } class ConcreteA : IfaceA { } class abstract BaseClassB<T> : IfaceB<T> { public virtual T Add(T t) { ... } public virtual void Add(IfaceA a) { ... } } class ConcreteB : BaseClassB<IfaceA> { // does not override one of the relevant methods } void code() { var concreteB = new ConcreteB(); // it will call void Add(IfaceA a) concreteB.Add(new ConcreteA()); } 

In any case, why does the compiler not warn me, or even why does it compile? Thanks so much for any answers.

+6
generics methods c # overloading dispatch
source share
3 answers

In accordance with the rules of clause 7.5.3.2, the C # 4 specification ("Better member function").

First (well, given that both methods are applicable), we need to check the conversion from argument types to parameter types. In this case, it is quite simple, because there is only one argument. Neither converting the argument type to the parameter type is โ€œbetterโ€ because both are converted from ConcreteA to IfaceA . Therefore, he proceeds to the next set of criteria, including this:

Otherwise, if MP has more specific parameters than MQ, then MP is better than MQ. Let {R1, R2, ..., RN} and {S1, S2, ..., SN} be unreasonable and unexpanded parameters of the parameters MP and MQ. MPs parameter types are more specific than MQ if for each parameter RX is not less specific than SX, and for at least one parameter, RX is more specific than SX: specific than SX:

  • A type parameter is less specific than a non-type parameter.
  • ...

Thus, although the conversion is equally good, overloading with IfaceA directly (and not through delegates) is considered "better" because an IfaceA type IfaceA more specific than a T type parameter.

It is not possible to force the compiler to warn about this behavior - this is just a normal overload resolution.

+2
source share

Because the compiler chooses the most specific first.

What happens if you call like this:

 void code() { var concreteB = new ConcreteB(); IfaceA x = concreteB.Add(new ConcreteA()); } 
+1
source share

This reminds me a bit of the โ€œType inference a-go-goโ€ in Jon Skeet BrainTeaser . If you do not want to trust the compiler, you can force it to select by calling Add<ConcreteA>(new ConcreteA())

+1
source share

All Articles