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

Свои методы

Чему вы научитесь

Чему вы научитесь:

  • объявлять методы с параметрами и возвращаемым значением;
  • вызывать методы с именованными аргументами и значениями по умолчанию;
  • объяснять, почему метод меняет только копию аргумента, и передавать саму переменную через ref и out;
  • писать рекурсивные методы с базовым случаем.
Копировальный аппарат Max(a, b): на стекле листы 3 и 8, а из лотка выходит копия листа 8

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

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

Зачем он нужен? Допустим, программе в трёх местах нужно выбрать большее из двух чисел. Без метода вы трижды напишете один и тот же if, а найдя в нём ошибку, будете исправлять её трижды. С методом вы пишете проверку один раз, а в нужных местах вызываете метод по имени:

C#
Console.WriteLine(Max(3, 8));   // 8
Console.WriteLine(Max(10, -2)); // 10

int Max(int a, int b)
{
    if (a > b)
    {
        return a;
    }
    return b;
}

Давайте разберём, что происходит при первом вызове:

  1. Max(3, 8) вызывает метод: значение 3 попадает в a, а 8 — в b.
  2. Тело метода выполняется сверху вниз. Условие 3 > 8 ложно, поэтому return a; пропускается.
  3. return b; завершает метод и отдаёт 8 туда, откуда его вызвали.
  4. Console.WriteLine печатает 8.

Второй вызов проходит тот же путь с другими числами: 10 > -2 истинно, и метод возвращает 10.

Объявление метода

Первая строка объявления, int Max(int a, int b), состоит из трёх частей:

  • int — тип результата: значение какого типа метод отдаст обратно;
  • Max — имя метода; в C# методы называют с большой буквы;
  • (int a, int b) — параметры: тип и имя каждого, через запятую.

За первой строкой в фигурных скобках идёт тело — инструкции, которые выполняются при каждом вызове.

Параметры и аргументы

В примере встретились два слова, которые часто путают:

  • параметр — переменная из объявления метода: a и b в int Max(int a, int b);
  • аргумент — значение, которое передают при вызове: 3 и 8 в Max(3, 8).

Аргументы попадают в параметры по порядку: первый в первый, второй во второй. Число и типы аргументов компилятор сверяет с объявлением. Аргументом может быть любое выражение подходящего типа: вызов Max(x + 1, 5) сначала вычислит x + 1.

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

Инструкция return

return делает две вещи сразу:

  • отдаёт значение туда, откуда вызвали метод;
  • тут же завершает метод: строки после сработавшего return уже не выполняются.

Метод с типом результата обязан дойти до return на любом пути через тело. В Max таких путей два: через return a; и через return b;.

Методы без результата

Здесь аналогия с копировальным аппаратом перестаёт работать. Аппарат всегда выдаёт лист, а метод может ничего не возвращать: например, только выводить текст на экран. Вместо типа результата у такого метода стоит void:

C#
Greet("Anna"); // Hello, Anna!
Greet("Oleg"); // Hello, Oleg!

void Greet(string name)
{
    Console.WriteLine("Hello, " + name + "!");
}

Greet("Anna") выполняет тело, в котором name равен "Anna", и печатает приветствие. Вызов такого метода — отдельная инструкция: его нельзя передать в Console.WriteLine или записать в переменную. Строка int x = Greet("Anna"); не скомпилируется, ведь void значит «результата нет».

В методе void тоже можно написать return;, без значения: такая инструкция сразу завершает метод.

Короткая форма через =>

Если метод вычисляет одно выражение, фигурные скобки и return можно заменить стрелкой =>:

C#
Console.WriteLine(Square(4)); // 16

int Square(int n) => n * n;

int Square(int n) => n * n; значит то же, что тело { return n * n; }. Такую форму используют для коротких методов, в том числе для методов void.

Где объявлять метод

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

Формально такой метод называется локальной функцией. Помните метод-точку входа <Main>$, который компилятор строит вокруг инструкций верхнего уровня? Ваш метод попадает внутрь него. Сам <Main>$ объявлен внутри класса Program — это метод класса. Методы класса устроены так же: тип результата, имя, параметры и тело.

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

В методе есть путь, на котором return не встречается:

C#
Console.WriteLine(Max(3, 8));

int Max(int a, int b) // ✗
{
    if (a > b)
    {
        return a;
    }
}
TEXT
error CS0161: 'Max(int, int)': not all code paths return a value

Программа не компилируется. Компилятор не запускает её и не знает, какие числа придут в Max, поэтому проверяет все пути через тело. Если a > b ложно, метод доходит до закрывающей скобки без return, и вернуть ему нечего. Исправление — последняя строка return b;, как в первом примере.

Главное

  • Метод объявляют так: тип результата, имя, параметры в скобках и тело; вызывают по имени, передавая аргументы.
  • Параметр — переменная из объявления, аргумент — значение из вызова.
  • return отдаёт результат и сразу завершает метод; метод с типом результата должен дойти до return на любом пути, а метод void ничего не возвращает.
  • Метод, объявленный среди инструкций верхнего уровня, формально называется локальной функцией.