Урок 8.1 — Методы и возврат значений
Функции в C#: DRY, return, void, static и область видимости.
Представь, что ты повар. Каждый раз, когда нужно почистить картошку, ты не изобретаешь нож заново — ты берёшь готовый инструмент. Методы в C# — это твои инструменты. Один раз написал, дал имя — и используешь сколько угодно раз. Программы без методов — это как кухня, где каждый раз варят суп, заново выращивая морковь.
Зачем нужны методы?
Методы решают несколько проблем сразу:
// ❌ Без метода — копируем код 3 раза
int a1 = 5 * 5;
Console.WriteLine(a1);
int a2 = 12 * 12;
Console.WriteLine(a2);
int a3 = 7 * 7;
Console.WriteLine(a3);
// ✅ С методом — один раз написали, 3 раза вызвали
static int Square(int x)
{
return x * x;
}
Console.WriteLine(Square(5)); // 25
Console.WriteLine(Square(12)); // 144
Console.WriteLine(Square(7)); // 49
Синтаксис метода
static тип Имя(параметры) { тело }
- static — модификатор (пока используем, позже разберёмся)
- тип — что метод возвращает:
int,string,double... Если ничего не возвращает —void - Имя — глагол в PascalCase:
CalculateSum,GetName,PrintMenu - параметры — входные данные, которые метод принимает (могут быть пустыми)
- тело — код, который выполняется при вызове
using System;
class Program
{
// Метод, который приветствует пользователя
static void SayHello()
{
Console.WriteLine("Привет, мир!");
}
// Метод, который возвращает сумму двух чисел
static int Add(int a, int b)
{
return a + b;
}
static void Main()
{
SayHello(); // вызов void-метода
int sum = Add(3, 5); // вызов с возвратом значения
Console.WriteLine(sum); // 8
}
}
return — возврат значения
Ключевое слово return решает две задачи:
- Возвращает результат вызывающему коду
- Завершает выполнение метода
static int Max(int a, int b)
{
if (a > b)
return a; // если a больше — выходим, возвращаем a
return b; // иначе возвращаем b
}
int result = Max(10, 7); // result = 10
Console.WriteLine(result);
// return может быть выражением любой сложности:
static double CircleArea(double radius)
{
return Math.PI * radius * radius;
}
Console.WriteLine(CircleArea(5)); // 78.53981633974483
⚠️ Важно: если метод объявлен с возвращаемым типом (не void), то return обязателен на всех путях выполнения. Компилятор проверит это. Если метод void, return использовать можно (просто return;), но не обязательно.
// Один метод — несколько return
static string Grade(int score)
{
if (score >= 90) return "Отлично";
if (score >= 75) return "Хорошо";
if (score >= 60) return "Удовлетворительно";
if (score >= 40) return "Неудовлетворительно";
return "Провал"; // дошли сюда — значит score < 40
}
Console.WriteLine(Grade(85)); // Хорошо
Console.WriteLine(Grade(95)); // Отлично
Console.WriteLine(Grade(30)); // Провал
Void-методы (без возврата)
Методы с типом void не возвращают никакого значения. Они выполняют действие: выводят текст, меняют состояние, записывают файл.
static void PrintHeader(string title)
{
Console.WriteLine("=".PadRight(40, '='));
Console.WriteLine($" {title}");
Console.WriteLine("=".PadRight(40, '='));
}
static void PrintSeparator()
{
Console.WriteLine("-".PadRight(40, '-'));
}
// Вызовы:
PrintHeader("Главное меню");
PrintSeparator();
// Void с return (досрочный выход):
static void PrintPositive(int number)
{
if (number < 0)
return; // досрочно выходим, ничего не печатаем
Console.WriteLine(number);
}
PrintPositive(5); // 5
PrintPositive(-3); // ничего не выведет
return; в void-методе — это как «стоп, дальше не идём». Он прерывает выполнение метода. Полезно при проверке условий в начале метода (guard clause).Локальные переменные и область видимости
Переменные, объявленные внутри метода, называются локальными. Они видны только в этом методе. Снаружи их нет:
static void MethodA()
{
int x = 10; // x видна только внутри MethodA
Console.WriteLine(x);
}
static void MethodB()
{
// Console.WriteLine(x); // ❌ Ошибка! x не видна здесь
int y = 20; // y видна только внутри MethodB
}
// Переменные в разных методах могут называться одинаково:
static void Foo()
{
int value = 1;
Console.WriteLine(value);
}
static void Bar()
{
int value = 2; // это другая переменная, не конфликтует
Console.WriteLine(value);
}
// Внутри метода тоже есть вложенные области:
static void ScopeDemo()
{
int outer = 100;
if (outer > 0)
{
int inner = 200; // видна только внутри if
Console.WriteLine(outer + inner); // 300
}
// Console.WriteLine(inner); // ❌ Ошибка! inner не видна
Console.WriteLine(outer); // 100 — ок
}
✅ Правило: переменная живёт от места объявления до конца блока { }, в котором она объявлена. Это называется областью видимости (scope).
Модификатор static
Пока мы пишем всё в классе Program с методом Main. Метод Main — статический. Чтобы вызывать наши методы из Main, они тоже должны быть static (пока что). Позже, когда изучим классы и объекты, разберёмся с этим подробнее.
class Program
{
// Статический метод — можно вызвать без создания объекта
static void Greet(string name)
{
Console.WriteLine($"Привет, {name}!");
}
// Main — точка входа, тоже static
static void Main()
{
Greet("Анна"); // вызываем статический метод
Greet("Борис");
}
}
// Без static (метод экземпляра) — будет позже:
class Calculator
{
public int Add(int a, int b) // не static — нужен объект
{
return a + b;
}
}
// var calc = new Calculator();
// calc.Add(3, 5); // так вызываются нестатические методы
static к своим методам, чтобы вызывать их из Main. В следующих модулях разберём разницу.Практический пример: калькулятор через методы
Разобьём калькулятор на методы — каждый выполняет свою задачу:
using System;
class Program
{
static void PrintMenu()
{
Console.WriteLine("1. Сложить");
Console.WriteLine("2. Вычесть");
Console.WriteLine("3. Умножить");
Console.WriteLine("4. Разделить");
Console.WriteLine("5. Выйти");
}
static int ReadNumber(string prompt)
{
Console.Write(prompt);
return int.Parse(Console.ReadLine());
}
static int Add(int a, int b) => a + b;
static int Subtract(int a, int b) => a - b;
static int Multiply(int a, int b) => a * b;
static double Divide(int a, int b) => (double)a / b;
static void Main()
{
while (true)
{
PrintMenu();
int choice = ReadNumber("Выбери операцию: ");
if (choice == 5) break;
int x = ReadNumber("Первое число: ");
int y = ReadNumber("Второе число: ");
switch (choice)
{
case 1:
Console.WriteLine($"Результат: {Add(x, y)}");
break;
case 2:
Console.WriteLine($"Результат: {Subtract(x, y)}");
break;
case 3:
Console.WriteLine($"Результат: {Multiply(x, y)}");
break;
case 4:
if (y == 0)
Console.WriteLine("На ноль делить нельзя!");
else
Console.WriteLine($"Результат: {Divide(x, y):F2}");
break;
}
}
}
}
Мини-тест
Вопрос 1
Что будет в переменной result: static int Foo(int x) { return x * 2; } int r = Foo(5);?
Ответ: 10. Метод возвращает число, умноженное на 2.
Вопрос 2
Какой тип должен быть у метода, который не возвращает значение?
Ответ: void. Такой метод выполняет действие, но не возвращает результат.
Вопрос 3
Что выведет код: static int Test() { return 1; return 2; } Console.WriteLine(Test());?
Ответ: 1. После первого return метод завершается, второй return никогда не выполнится.
Вопрос 4
Где можно использовать переменную, объявленную внутри блока if { }?
Ответ: Только внутри этого блока if { }. После закрывающей скобки переменная не видна (область видимости).
Задание для тренировки
Напиши программу «Анализ чисел», которая:
- Содержит метод
static int[] GenerateArray(int size, int min, int max)— создаёт массив случайных чисел - Содержит метод
static int Sum(int[] arr)— сумму элементов - Содержит метод
static double Average(int[] arr)— среднее - Содержит метод
static (int Min, int Max) MinMax(int[] arr)— минимум и максимум - Содержит метод
static void PrintStats(int[] arr)— выводит всё на экран - В Main создай массив из 15 чисел (от -50 до 50) и выведи статистику
using System;
class Program
{
static int[] GenerateArray(int size, int min, int max)
{
int[] arr = new int[size];
Random rnd = new Random();
for (int i = 0; i < size; i++)
arr[i] = rnd.Next(min, max + 1);
return arr;
}
static int Sum(int[] arr)
{
int sum = 0;
foreach (int n in arr) sum += n;
return sum;
}
static double Average(int[] arr)
{
return (double)Sum(arr) / arr.Length;
}
static (int Min, int Max) MinMax(int[] arr)
{
int min = arr[0], max = arr[0];
foreach (int n in arr)
{
if (n < min) min = n;
if (n > max) max = n;
}
return (min, max);
}
static void PrintStats(int[] arr)
{
Console.WriteLine("Массив: " + string.Join(", ", arr));
Console.WriteLine($"Сумма: {Sum(arr)}");
Console.WriteLine($"Среднее: {Average(arr):F2}");
var (min, max) = MinMax(arr);
Console.WriteLine($"Мин: {min}, Макс: {max}");
Console.WriteLine($"Длина: {arr.Length}");
}
static void Main()
{
int[] numbers = GenerateArray(15, -50, 50);
PrintStats(numbers);
}
}
Что важно запомнить
static тип Имя(параметры) { тело }. Вызывается по имени: Имя(аргументы).void — ничего не возвращает.CalculateTotal, GetUserName.Тест: 8.1: Методы и возврат значений
3 вопроса