c# Универсальный перегруженный метод, диспетчеризирующий неоднозначный

Я просто поразил ситуацию, где отправка метода была неоднозначна и задалась вопросом, мог ли кто-либо объяснить, на каком основании компилятор (.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());
}

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

7
задан Sebastian 18 May 2010 в 07:11
поделиться

3 ответа

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

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

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

  • Типовой параметр менее специфичен, чем нетиповой.
  • ...

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

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

2
ответ дан 7 December 2019 в 14:29
поделиться

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

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

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

    IfaceA  x = concreteB.Add(new ConcreteA()); 
} 
1
ответ дан 7 December 2019 в 14:29
поделиться

Это несколько напоминает мне "Type inference a-go-go" в Jon Skeet's BrainTeaser. Если вы не хотите доверять компилятору, вы можете заставить его сделать выбор, вызвав Add(new ConcreteA())

1
ответ дан 7 December 2019 в 14:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: