Метод в C# — это именованный блок кода внутри класса или структуры, который выполняет одну задачу и при необходимости возвращает результат. Метод объявляют один раз, а вызывают сколько угодно раз, передавая ему входные данные через параметры.
Содержание
- Из чего состоит объявление метода
- Модификаторы доступа
- Способы передачи параметров
- Необязательные и именованные аргументы
- Перегрузка методов
- Статические и экземплярные методы
- Возвращаемое значение и выход из метода
- Короткая запись: expression-bodied и локальные функции
- Выводы
- Где применяется / связь с практикой
- FAQ
Ниже разберем, из чего состоит объявление метода, чем отличаются модификаторы доступа, как передаются параметры (по значению, ref, out, in, params), что такое необязательные и именованные аргументы, перегрузка, статические и экземплярные методы, а также короткая запись через expression-bodied и локальные функции.
Из чего состоит объявление метода
Минимальный рабочий пример, который можно скопировать и запустить:
using System;
class Program
{
// модификаторы | тип результата | имя | параметры
static int Sum(int a, int b)
{
return a + b; // тело метода
}
static void Main()
{
int result = Sum(2, 3);
Console.WriteLine(result); // выведет 5
}
}
Объявление читается слева направо: сначала модификаторы (static), затем тип возвращаемого значения (int), имя метода (Sum), список параметров в круглых скобках и тело в фигурных скобках. Вызов — это имя метода и фактические аргументы: Sum(2, 3).
Тип void означает, что метод ничего не возвращает. Точка входа программы Main — это обычный метод с зарезервированным именем; его может вызвать среда выполнения при старте.
Модификаторы доступа
Модификатор доступа задает, откуда виден член класса. Если модификатор не указан, член класса по умолчанию получает private.
public— виден отовсюду;private— только внутри своего класса (значение по умолчанию для членов класса);protected— внутри класса и его наследников;internal— внутри той же сборки (проекта);protected internal— внутри сборки или у наследников;private protected— у наследников внутри той же сборки.
Модификатор доступа и static — это разные вещи: первый отвечает за видимость, второй за то, привязан ли метод к объекту или к типу.
Способы передачи параметров
По умолчанию параметр передается по значению: метод получает копию, и изменение параметра не затрагивает исходную переменную. Ключевые слова ref, out и in меняют это поведение, а params позволяет принять переменное число аргументов.
| Способ | Инициализация до вызова | Метод может менять | Обязан присвоить внутри | Когда применять |
|---|---|---|---|---|
| по значению | не требуется | только копию | нет | обычная передача данных |
ref |
обязательна | да | нет | двусторонний обмен через переменную |
out |
не требуется | да, записывает | да, на всех путях выхода | вернуть несколько значений |
in |
обязательна | нет, только чтение | нет | большая структура без копирования |
params |
не требуется | работает с массивом | нет | переменное число аргументов |
Разница между ref, out и in сводится к трем вопросам: нужно ли инициализировать переменную до вызова, может ли метод ее менять и обязан ли он что-то записать. ref — двусторонний и требует готового значения. out — для вывода: значение до вызова не нужно, но метод обязан присвоить его перед выходом. in — только чтение: метод видит переменную по ссылке, но менять не вправе.
Пример ref: переменная должна быть инициализирована заранее.
static void Increment(ref int x)
{
x++;
}
int n = 5; // ref требует значения до вызова
Increment(ref n);
Console.WriteLine(n); // выведет 6
Пример out показывает типичную ошибку — не присвоить параметр на всех путях выхода:
static bool TryPositive(string s, out int value)
{
if (int.TryParse(s, out value) && value > 0)
return true;
return false; // value присвоен не везде
}
Компилятор откажется собирать такой код:
error CS0177: выходной параметр "value" должен быть присвоен, прежде чем управление покинет текущий метод
Исправление — присвоить value на ветке, где метод возвращает false:
static bool TryPositive(string s, out int value)
{
if (int.TryParse(s, out value) && value > 0)
return true;
value = 0; // присваиваем на всех путях выхода
return false;
}
Параметр in передает данные по ссылке только для чтения — это полезно для больших структур, чтобы не копировать их.
struct Point { public double X; public double Y; }
static double Length(in Point p)
{
// p доступен только для чтения: строка p.X = 0 не скомпилируется
return Math.Sqrt(p.X * p.X + p.Y * p.Y);
}
Параметр params принимает переменное число аргументов одного типа и внутри метода работает как массив. Он должен быть последним в списке параметров.
static int SumAll(params int[] numbers)
{
int total = 0;
foreach (int x in numbers)
total += x;
return total;
}
Console.WriteLine(SumAll(1, 2, 3, 4)); // выведет 10
Console.WriteLine(SumAll()); // выведет 0
Необязательные и именованные аргументы
Необязательный параметр получает значение по умолчанию прямо в объявлении. Если при вызове аргумент не передан, подставляется значение по умолчанию. Такие параметры идут после обязательных.
Именованные аргументы позволяют указать значение по имени параметра, а не по позиции — это удобно, когда параметров много.
static string Greet(string name, string greeting = "Привет")
{
return $"{greeting}, {name}!";
}
Console.WriteLine(Greet("Аня")); // Привет, Аня!
Console.WriteLine(Greet("Аня", "Здравствуйте")); // Здравствуйте, Аня!
Console.WriteLine(Greet(greeting: "Хай", name: "Аня")); // именованные аргументы
Перегрузка методов
Перегрузка — это несколько методов с одним именем, но разным набором параметров. Компилятор выбирает нужный по типам и числу аргументов. Важное ограничение: методы нельзя различать только по типу возвращаемого значения — отличаться должен список параметров.
static int Max(int a, int b) => a > b ? a : b;
static double Max(double a, double b) => a > b ? a : b;
Console.WriteLine(Max(3, 7)); // вызовется int-версия, выведет 7
Console.WriteLine(Max(2.5, 1.5)); // вызовется double-версия, выведет 2.5
Статические и экземплярные методы
Экземплярный метод работает с конкретным объектом и имеет доступ к его полям. Статический метод принадлежит типу, а не объекту, и вызывается через имя класса.
class Counter
{
private int count; // поле экземпляра
public static int Total; // общее поле для всех объектов
public void Add() // экземплярный метод
{
count++;
Total++;
}
public int Current() => count;
}
var c = new Counter();
c.Add();
Console.WriteLine(c.Current()); // 1, у этого объекта
Console.WriteLine(Counter.Total); // 1, общий счетчик через имя класса
Ориентир простой: если метод не обращается к данным конкретного объекта, его можно и стоит сделать статическим.
Возвращаемое значение и выход из метода
Если тип результата не void, метод обязан вернуть значение оператором return на всех путях выхода. Оператор return также досрочно прекращает работу метода, в том числе в void-методе (тогда после return значение не пишут).
static void PrintIfPositive(int x)
{
if (x <= 0)
return; // досрочный выход, дальше код не выполнится
Console.WriteLine($"Положительное: {x}");
}
Короткая запись: expression-bodied и локальные функции
Если тело метода — одно выражение, его записывают через => (expression-bodied метод). Это тот же метод, просто короче.
public int Square(int x) => x * x;
Локальная функция — это метод, объявленный внутри другого метода. Она видна только в нем и удобна для вспомогательной логики, которую не нужно выносить наружу.
static long Factorial(int n)
{
return Calc(n);
long Calc(int k) => k <= 1 ? 1 : k * Calc(k - 1); // локальная функция
}
Console.WriteLine(Factorial(5)); // выведет 120
Выводы
- Метод в C# — именованный блок кода в классе или структуре; объявляется один раз, вызывается многократно.
- По умолчанию параметры передаются по значению;
ref— двусторонний обмен,out— вернуть значение (обязателен для записи),in— только чтение,params— переменное число аргументов. - Перегрузка различает методы по списку параметров, но не по типу возвращаемого значения.
- Статический метод привязан к типу и вызывается через имя класса, экземплярный — к объекту и его полям.
- Одно выражение оформляют через
=>, вспомогательную логику — локальной функцией внутри метода.
Где применяется / связь с практикой
Методы — это базовый строительный блок любого приложения на C#: от точки входа Main до бизнес-логики сервисов и обработчиков в ASP.NET. Умение выбрать способ передачи параметров и грамотно разбить код на методы напрямую влияет на читаемость и сопровождаемость проекта.
Освойте тему на практике
Разобрать методы, классы и синтаксис C# на практике под руководством преподавателя можно на курсе C# Basic. Если хочется сначала посмотреть формат и уровень, загляните в расписание открытых уроков Otus — там регулярно проходят бесплатные занятия по C# и .NET.
FAQ
Можно ли объявить метод вне класса?
В обычном коде нет: метод принадлежит классу, структуре или другому типу. Исключение — top-level statements в файле с точкой входа, где компилятор сам оборачивает код в скрытый класс.
Чем метод отличается от функции?
В C# это фактически синонимы: функцию, объявленную внутри типа, называют методом. Термин «локальная функция» подчеркивает лишь то, что она объявлена внутри другого метода.
Сколько значений может вернуть метод через return?
Через return — одно. Чтобы вернуть несколько, используют параметры out, либо возвращают кортеж вида (int, int), либо отдельный объект или структуру.



