开发者

c# Generic overloaded method dispatching ambiguous

I just hit a situation where a method dispatch was ambiguous and wondered if anyone could explain on what basis the compiler (.NET 4.0.30319) chooses what 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? Thank you very much for any answers.


It follows the rules in section 7.5.3.2 of the C# 4 specification ("Better function member").

First (well, after seeing that both methods are applicable) we need to check the conversions from argument types to parameter types. In this case it's reasonably simple because there's only one argument. Neither conversion of argument type to parameter type is "better" because both are converting from ConcreteA to IfaceA. It therefore moves on to the next set of criteria, including this:

Otherwise, if MP has more specific parameter types than MQ, then MP is better than MQ. Let {R1, R2, …, RN} and {S1, S2, …, SN} represent the uninstantiated and unexpanded parameter types of MP and MQ. MP’s parameter types are more specific than MQ’s 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.
  • ...

So even though the conversion is equally good, the overload using IfaceA directly (rather than via delegates) is deemed "better" because a parameter of type IfaceA is more specific than a parameter of type T.

There's no way of getting the compiler to warn on this behaviour - it's just normal overload resolution.


Because the compiler chooses the most specific first.

What happens if you call like so:

void code()   
{ 
    var concreteB = new ConcreteB(); 

    IfaceA  x = concreteB.Add(new ConcreteA()); 
} 


This somewhat reminds me of the "Type inference a-go-go" in Jon Skeet's BrainTeaser. If you do not want to trust the compiler, you might want to force its choice by calling Add<ConcreteA>(new ConcreteA())

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜