Необязательные и именованные аргументы
В прошлом уроке метод получал все аргументы по порядку, и ни одного нельзя было пропустить. Но у многих приборов есть режим по умолчанию. Нажали кнопку на копировальном аппарате — он делает одну копию. Нужно пять — набираете число копий, а если одна устраивает, ничего не трогаете.
Параметрам метода тоже можно задать значения по умолчанию. Вот метод, который рисует линию из символов. Какой символ и сколько раз его повторить, решают параметры:
Line(); // ----------
Line('*', 5); // *****
Line('='); // ==========
void Line(char symbol = '-', int length = 10)
{
for (int i = 0; i < length; i++)
{
Console.Write(symbol);
}
Console.WriteLine();
}Значение по умолчанию
Давайте разберём объявление и вызовы по порядку:
char symbol = '-'иint length = 10— параметры со значениями по умолчанию. Такой параметр называют необязательным: аргумент для него можно не передавать.Line()не передаёт ничего:symbolполучает'-',lengthполучает10, и метод рисует 10 дефисов.Line('*', 5)передаёт оба аргумента, и значения по умолчанию не нужны.Line('=')передаёт только первый аргумент:symbolполучает'=', аlength— значение по умолчанию10.
Цикл печатает символ нужное число раз через Console.Write, а Console.WriteLine() без аргумента в конце переводит строку.
Для необязательных параметров действуют два правила:
- они стоят в списке после всех обязательных;
- значение по умолчанию должно быть известно уже при компиляции, например число, символ, строка,
trueилиfalse. Переменную туда подставить нельзя.
Здесь картинка с копировальным аппаратом неточна. Аппарат может помнить число копий, набранное в прошлый раз, а метод ничего не запоминает. Значение по умолчанию подставляется в каждом вызове заново, если аргумент для этого параметра не передан.
Именованные аргументы
А если нужна линия из дефисов длиной 3? По порядку первый аргумент не пропустить: Line(3) не скомпилируется, потому что первым компилятор ждёт символ для symbol.
Для этого есть именованные аргументы: перед значением пишут имя параметра и двоеточие. Такой аргумент попадает в параметр с этим именем, а не в параметр на той же позиции:
Line(length: 3); // ---
Line(length: 4, symbol: '+'); // ++++Разберём оба вызова:
Line(length: 3)передаёт толькоlength, аsymbolполучает значение по умолчанию'-';Line(length: 4, symbol: '+')перечисляет аргументы не в том порядке, что в объявлении, и это не ошибка: компилятор раскладывает их по именам.
Именованный аргумент полезен и тогда, когда ничего не пропускается. По вызову Line('*', length: 5) сразу видно, что значит 5, а в Line('*', 5) это приходится вспоминать.
Обычные и именованные аргументы можно смешивать. Обычные пишите первыми: компилятор раскладывает их по позициям слева направо.
Частая ошибка
Необязательный параметр поставили перед обязательным:
Line('*', 5);
void Line(char symbol = '-', int length) // ✗
{
for (int i = 0; i < length; i++)
{
Console.Write(symbol);
}
Console.WriteLine();
}error CS1737: Optional parameters must appear after all required parametersПрограмма не компилируется. Обычные аргументы заполняют параметры слева направо, и пропустить первый параметр, передав второй, нельзя. Значит, значение по умолчанию у symbol не пригодилось бы ни в одном обычном вызове. Поэтому необязательные параметры всегда идут в конце списка: void Line(int length, char symbol = '-').
Главное
- Параметр со значением по умолчанию необязателен: если аргумент не передан, метод получает значение по умолчанию, и так в каждом вызове заново.
- Необязательные параметры стоят после обязательных, а значение по умолчанию должно быть известно при компиляции.
- Именованный аргумент, например
length: 3, попадает в параметр по имени: именованные аргументы можно перечислять в любом порядке и пропускать необязательные параметры перед ними.