Перегрузка метода. Как это работает?

Предположим, что у меня есть две перегруженные функции.

public static void Main(string[]args)
{
     int x=3;
     fn(x); 
}

static void fn(double x)
{ 
    Console.WriteLine("Double");
}

static void fn(float x)
{
    Console.WriteLine("Float");
}

Почему компилятор выбирает функцию float?

Ответ 1

Он следует правилам раздела 7.5.3.2 спецификации С# 4.

int неявно конвертируется как в float, так и в double, поэтому применимы оба метода-кандидата. Однако преобразование с int в float является "лучше, чем" преобразование от int до double в соответствии с разделом 7.5.3.2-7.5.3.5:

Учитывая два разных типа T1 и T2, T1 является лучшей целью преобразования, чем T2, если выполняется хотя бы одно из следующих действий:

  • Существует неявное преобразование из T1 в T2, и не существует никакого неявного преобразования из T2 в T1.
  • ... [неуместно в этом случае]

Здесь существует неявное преобразование от float до double, но неявное преобразование от double до float - поэтому float является лучшей целью преобразования, чем double.

Ответ 2

Джон ответ, конечно, прав. Чтобы добавить немного более подробно: принцип проектирования здесь заключается в том, что более "более конкретный" метод лучше. Если у вас есть:

void M(object x){}
void M(Animal x){}
void M(Giraffe x){}

и вы назвали M(new Giraffe()), очевидно, вам нужно точное совпадение. Если вы назвали M(new Tiger()), лучшим совпадением является "Животное", потому что тигр - это своего рода животное, тигр - это своего рода объект, но животное более специфично, чем объект. Откуда мы знаем, что животное более специфично, чем объект? Потому что каждое животное является объектом, но не каждый объект является животным, поэтому животное должно быть более конкретным.

Если вы позвонили M(null), мы бы выбрали версию жирафа. Жираф более специфичен, чем животное, потому что каждый жираф - это животное, но не каждое животное - жираф.

В вашем примере float лучше, чем double, потому что он более конкретный. Каждый float может быть преобразован в double, но не каждый двойной может быть преобразован в float, поэтому float более конкретный. Подобно тому, как каждое животное может быть преобразовано в объект, но не каждый объект может быть преобразован в животное, поэтому животное более конкретное.