Перейти к содержимому
Теория · Методы · урок 3 из 8

Необязательные и именованные аргументы

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

Параметрам метода тоже можно задать значения по умолчанию. Вот метод, который рисует линию из символов. Какой символ и сколько раз его повторить, решают параметры:

C#
Line();       // ----------
Line('*', 5); // *****
Line('=');    // ==========

void Line(char symbol = '-', int length = 10)
{
    for (int i = 0; i < length; i++)
    {
        Console.Write(symbol);
    }
    Console.WriteLine();
}

Значение по умолчанию

Давайте разберём объявление и вызовы по порядку:

  1. char symbol = '-' и int length = 10 — параметры со значениями по умолчанию. Такой параметр называют необязательным: аргумент для него можно не передавать.
  2. Line() не передаёт ничего: symbol получает '-', length получает 10, и метод рисует 10 дефисов.
  3. Line('*', 5) передаёт оба аргумента, и значения по умолчанию не нужны.
  4. Line('=') передаёт только первый аргумент: symbol получает '=', а length — значение по умолчанию 10.

Цикл печатает символ нужное число раз через Console.Write, а Console.WriteLine() без аргумента в конце переводит строку.

Для необязательных параметров действуют два правила:

  • они стоят в списке после всех обязательных;
  • значение по умолчанию должно быть известно уже при компиляции, например число, символ, строка, true или false. Переменную туда подставить нельзя.

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

Именованные аргументы

А если нужна линия из дефисов длиной 3? По порядку первый аргумент не пропустить: Line(3) не скомпилируется, потому что первым компилятор ждёт символ для symbol.

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

C#
Line(length: 3);              // ---
Line(length: 4, symbol: '+'); // ++++

Разберём оба вызова:

  • Line(length: 3) передаёт только length, а symbol получает значение по умолчанию '-';
  • Line(length: 4, symbol: '+') перечисляет аргументы не в том порядке, что в объявлении, и это не ошибка: компилятор раскладывает их по именам.

Именованный аргумент полезен и тогда, когда ничего не пропускается. По вызову Line('*', length: 5) сразу видно, что значит 5, а в Line('*', 5) это приходится вспоминать.

Обычные и именованные аргументы можно смешивать. Обычные пишите первыми: компилятор раскладывает их по позициям слева направо.

Частая ошибка

Необязательный параметр поставили перед обязательным:

C#
Line('*', 5);

void Line(char symbol = '-', int length) // ✗
{
    for (int i = 0; i < length; i++)
    {
        Console.Write(symbol);
    }
    Console.WriteLine();
}
TEXT
error CS1737: Optional parameters must appear after all required parameters

Программа не компилируется. Обычные аргументы заполняют параметры слева направо, и пропустить первый параметр, передав второй, нельзя. Значит, значение по умолчанию у symbol не пригодилось бы ни в одном обычном вызове. Поэтому необязательные параметры всегда идут в конце списка: void Line(int length, char symbol = '-').

Главное

  • Параметр со значением по умолчанию необязателен: если аргумент не передан, метод получает значение по умолчанию, и так в каждом вызове заново.
  • Необязательные параметры стоят после обязательных, а значение по умолчанию должно быть известно при компиляции.
  • Именованный аргумент, например length: 3, попадает в параметр по имени: именованные аргументы можно перечислять в любом порядке и пропускать необязательные параметры перед ними.