c # Общий перегруженный метод отправки неоднозначно - PullRequest
6 голосов
/ 18 мая 2010

Я просто столкнулся с ситуацией, когда отправка метода была неоднозначной, и мне было интересно, если кто-нибудь может объяснить, на каком основании компилятор (.NET 4.0.30319) выбирает, какую перегрузку вызывать

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());
}

В любом случае, почему компилятор не предупреждает меня или даже почему он компилируется? Большое спасибо за любые ответы.

Ответы [ 3 ]

2 голосов
/ 18 мая 2010

Следует правилам раздела 7.5.3.2 спецификации C # 4 («Лучший функциональный член»).

Во-первых (хорошо, увидев, что оба метода применимы ), нам нужно проверить преобразования типов аргументов в типы параметров. В этом случае это достаточно просто, потому что есть только один аргумент. Ни одно преобразование типа аргумента в тип параметра не является «лучшим», поскольку оба преобразуются из ConcreteA в IfaceA. Поэтому он переходит к следующему набору критериев, включая этот:

В противном случае, если MP имеет более конкретную Типы параметров, чем MQ, то MP лучше чем MQ. Пусть {R1, R2,…, RN} и {S1, S2,…, SN} представляют собой необоснованный и нерасширенный Типы параметров MP и MQ. член парламента типы параметров являются более конкретными, чем MQ, если для каждого параметра RX не менее специфичен, чем SX, а для хотя бы один параметр, RX больше специфичнее, чем SX: специфично, чем SX:

  • Параметр типа менее специфичен, чем параметр без типа.
  • ...

Таким образом, даже если преобразование одинаково хорошо, перегрузка с использованием IfaceA напрямую (а не через делегатов) считается "лучшей", поскольку параметр типа IfaceA более специфичен, чем параметр типа T.

Нет способа заставить компилятор предупреждать об этом поведении - это просто нормальное разрешение перегрузки.

1 голос
/ 18 мая 2010

Это несколько напоминает мне «Вывод типа a-go-go» в BrainTeaser Джона Скита Если вы не хотите доверять компилятору, вы можете заставить его сделать выбор, вызвав Add<ConcreteA>(new ConcreteA())

1 голос
/ 18 мая 2010

Поскольку компилятор сначала выбирает наиболее конкретное.

Что произойдет, если вы позвоните так:

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

    IfaceA  x = concreteB.Add(new ConcreteA()); 
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...