Подтвердить что ты не робот

Два метода, которые отличаются только необязательными параметрами

Во время копания в моей кодовой базе я нашел то, что меня поразило: пары функций, которые отличаются только необязательными параметрами, здесь один пример:

public static List<AvailableDay> Find(string mailboxCalendarId, string[] typeTrameCles, DateTime dateMin, bool hasPhNonUrgent, bool hasPhUrgence, bool hasPhUrgenceDuJour)
public static List<AvailableDay> Find(string mailboxCalendarId, string[] typeTrameCles, DateTime dateMin, bool hasPhNonUrgent, bool hasPhUrgence, bool hasPhUrgenceDuJour, int maxDaysResultCout = 1)

то, что я нахожу очень странным, заключается в том, что компилятор им доволен. Каково объяснение этого? Я что-то пропустил?

4b9b3361

Ответ 1

Это абсолютно правильный код. В вашей ситуации, однако, необязательный параметр никогда не используется, поскольку компилятор всегда будет предпочитать первую перегрузку, когда метод вызывается шестью параметрами.

От С# в глубину:

Когда вы сталкиваетесь с выбором между методом, который требует, чтобы компилятор заполнил необязательные значения параметров, а другой - нет, если методы в противном случае "привязаны" (т.е. преобразование нормальных аргументов не определило победителя), перегрузка разрешение будет выбирать тот, где вызывающий пользователь явно указал все аргументы.

Бывают ситуации, когда компилятор выбирает первую перегрузку поверх второй, потому что более конкретный метод скрыт. Вот несколько искусственный пример:

interface Foo {
    void Bar(int a, int b = 1);
}

class FooImpl : Foo {
    public void Bar(int a, int b) {
        Console.WriteLine("bar/2");
    }
    public void Bar(int a) {
        Console.WriteLine("bar/1");
    }
}

Если вы сделаете это

Foo f1 = new FooImpl();
f1.Bar(1); // Here, Bar(int a, int b = 1) is the only choice

bar/2 печатается, но если вы сделаете это

FooImpl f2 = new FooImpl();
f2.Bar(1); // Here Bar(int a) of the implementation wins

bar/1 печатается (демонстрация).

Ответ 2

Сначала давайте понять, что такое необязательный параметр

Необязательный параметр - это просто синтаксический сахар в С#.

Если у вас есть следующий метод, который использует необязательный параметр:

public void DeleteFiles(string extension = "*.*")

Реальная сигнатура этого метода

public void DeleteFiles(string extension)

Компилятор делает трюк здесь, когда вы используете этот метод следующим образом:

obj.DeleteFiles();

Когда компилятор выполнял свою работу, он получил вызов DeleteFiles без параметров, и он попытался найти его, но он не мог так попытаться найти и перегрузить, используя дополнительный параметр который может совпадать, на этот раз он нашел DeleteFile (строка), и теперь он делает трюк.

Фактически скомпилированный код будет таким:

var extension = "*.*";
obj.DeleteFiles(extension);

Итак, если вы попытаетесь сделать этот код:

public class A
{
    public void DeleteFiles(string extension = "*.*")
    {
    }

    public void DeleteFiles(string extension2)
    {
    }
}

Компилятор выдаст следующее сообщение об ошибке:

Ошибка CS0111: Тип 'A' уже определяет элемент с именем 'DeleteFiles' с теми же параметрами

Теперь зададим вопрос

Теперь у нас есть этот класс

public class A
{
    public void DeleteFiles(string folderPath)
    {
    }

    public void DeleteFiles(string folderPath, string extension = "*.*")
    {
    }
}

Реальный код в этом случае

public class A
{
    public void DeleteFiles(string folderPath)
    {
    }

    public void DeleteFiles(string folderPath, string extension)
    {
    }
}

Затем у вас есть этот код:

aInstance.DeleteFiles("path")

Компилятор будет выглядеть, если есть метод DeleteFiles, который получает один параметр. Он найдет его.

Заключение

Таким образом, в этом случае необязательная функция параметра никогда не будет использоваться, потому что есть совершенная сигнатура метода, которая заставляет компилятор никогда не пытаться найти другую подпись, которая использовала необязательный параметр.