JavaRush /Курсы /C# SELF /Перегрузка методов (Method Overloading)

Перегрузка методов (Method Overloading)

C# SELF
21 уровень , 1 лекция
Открыта

1. Введение

В реальной жизни многие действия — словно многофункциональные швейцарские ножи: одна и та же команда может работать с разными наборами инструментов. Например, представьте себе банкомат: если вы вставили карту — банкомат спрашивает пин-код; если ввели номер телефона — банкомат ожидает код подтверждения из SMS. Действие одно — "проверить пользователя", но способы разные.

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

Конечно, можно назвать методы как-нибудь по-разному: SumTwo, SumThree, SumArray. Но программисты ленивы (не зря говорят, что лень — двигатель прогресса). К тому же, так код станет менее читаемым.

Перегрузка метода

Перегрузка методов — это способ "заставить" один и тот же метод работать с разными наборами параметров, при этом имя метода не меняется. Это одна из форм полиморфизма, но не связанная с наследованием.

Перегрузка метода — это возможность создавать в одном классе (или структуре) несколько методов с одинаковым именем, но с разными списками параметров (по типу, количеству и/или порядку).

Сигнатура метода

Сигнатура метода в C# — это его имя плюс тип(ы) и порядок параметров. Возвращаемый тип метода не входит в сигнатуру! Это часто приводит к неожиданным ошибкам (о них расскажу чуть позже).

2. Перегрузка в действии: простые примеры

Давайте создадим класс Greeter, который будет приветствовать пользователей по-разному: просто по имени, по имени и возрасту, или вообще без параметров.


public class Greeter
{
    // Приветствие без параметров
    public void Greet()
    {
        Console.WriteLine("Привет, мир!");
    }

    // Приветствие с именем
    public void Greet(string name)
    {
        Console.WriteLine($"Привет, {name}!");
    }

    // Приветствие с именем и возрастом
    public void Greet(string name, int age)
    {
        Console.WriteLine($"Привет, {name}! Тебе уже {age} лет? Неплохо!");
    }
}

Теперь можно вызвать любой из этих методов, и компилятор C# сам выберет нужный вариант — ориентируясь на количество и типы переданных параметров.

var greeter = new Greeter();
greeter.Greet();                // Привет, мир!
greeter.Greet("Аня");           // Привет, Аня!
greeter.Greet("Пётр", 23);      // Привет, Пётр! Тебе уже 23 лет? Неплохо!

3. Различие по типу и количеству параметров

Перегрузка работает, если методы различаются:

  • количеством параметров,
  • типом хотя бы одного параметра,
  • порядком типов параметров (но тут надо быть осторожнее).

Попробуем добавить ещё одну перегрузку, принимающую только возраст:


public void Greet(int age)
{
    Console.WriteLine($"Столько лет — это круто! ({age} лет)");
}

Теперь вызовы:

greeter.Greet(10);          // Столько лет — это круто! (10 лет)

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


// Ошибка компиляции!
public int Foo(string s) { ... }
public double Foo(string s) { ... }
Перегрузка только по возвращаемому типу невозможна!

Компилятор будет ругаться: "Уже определён метод Foo(string), давай что-нибудь посложнее!"

4. Перегрузка и стандартная библиотека C#

Перегрузка — это не только наш выдуманный Greet. Откроем документацию .NET для Console.WriteLine:

Сигнатура Назначение
WriteLine()
Печатает пустую строку
WriteLine(string)
Печатает строку
WriteLine(int)
Печатает целое число
WriteLine(double)
Печатает дробное число
WriteLine(string, object)
Форматирует строку с одним аргументом
WriteLine(string, params object[])
Форматирует с несколькими аргументами

Это всё перегрузки одного и того же метода — WriteLine. Теперь вы понимаете, почему вы всегда можете делать:

Console.WriteLine("Просто строка");
Console.WriteLine(123);
Console.WriteLine(2.5);
Console.WriteLine("Сумма: {0}", 42);

И компилятор всегда трактует ваш вызов корректно!

5. Как компилятор выбирает, какую перегрузку вызвать?

Здесь всё строго: он смотрит на типы и количество фактически переданных аргументов. Небольшая табличка для наглядности:

Вызов Какая версия сработает?
greeter.Greet()
void Greet()
greeter.Greet(75)
void Greet(int)

Что будет при неоднозначности?

Иногда ситуация выходит из-под контроля. Пример неоднозначной перегрузки — компилятор не сможет выбрать нужную версию


public void Print(int a, double b) { ... }
public void Print(double a, int b) { ... }

printer.Print(5, 10); 
// Ошибка: двусмысленность — какое Print вызывать? (оба вроде бы подходят)

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

6. params — переменное количество параметров

Допустим, вы хотите реализовать метод, который принимает неопределённое количество чисел. Вам на помощь придёт ключевое слово params.


public void SumAll(params int[] numbers)
{
    int sum = 0;
    foreach (int n in numbers)
        sum += n;
    Console.WriteLine($"Сумма: {sum}");
}
Метод с переменным числом параметров ( params)

Теперь вы можете вызывать:

SumAll(1, 2, 3);           // Сумма: 6
SumAll(10, 20);            // Сумма: 30
SumAll();                  // Сумма: 0

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

7. Перегрузка и модификаторы параметров (ref, out, in)

C# различает методы по модификаторам параметров (то есть, сигнатура void Foo(int a) отличается от void Foo(ref int a), и оба могут существовать в одном классе):

public void SetValue(int a)
{
    a = 42;
}

public void SetValue(ref int a)
{
    a = 100;
}
Перегрузка по модификатору ref

Вызов без ref попадёт в первую версию, с ref — во вторую:

int n = 5;
SetValue(n);     // n остается 5 (копируется значение)
SetValue(ref n); // n становится 100

8. Схема: что такое перегрузка


      +----------+
      |  MyClass |
      +----------+
           |
           |            (фрагмент методов)
    +-----------------------+
    |   void Foo()          |
    |   void Foo(int a)     |
    |   void Foo(string s)  |
    |   void Foo(int a, int b) |
    +-----------------------+
Схема перегрузки методов в классе

А если представить в коде:

// Вызываем перегруженные версии метода Foo():
var mc = new MyClass();
mc.Foo();              // void Foo()
mc.Foo(5);             // void Foo(int)
mc.Foo("Hello");       // void Foo(string)
mc.Foo(2, 3);          // void Foo(int, int)

9. Пример: перегрузим методы в нашем приложении

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


public class Animal
{
    public string Name { get; set; }

    // Метод для издания звука
    public virtual void MakeSound()
    {
        Console.WriteLine("Некий непонятный звук...");
    }

    // Перегруженный метод: звук с указанной громкостью
    public void MakeSound(int volume)
    {
        Console.WriteLine($"Животное издаёт звук громкостью {volume} дБ.");
    }
}

public class Dog : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("Гав!");
    }

    // Перегруженный метод: гавканье с громкостью
    public void MakeSound(int volume)
    {
        Console.WriteLine($"Гав! (громкость: {volume} дБ)");
    }
}

Попробуйте такие вызовы:

Dog rex = new Dog();
rex.MakeSound();           // Гав!
rex.MakeSound(75);         // Гав! (громкость: 75 дБ)

Обратите внимание: в классе-наследнике (Dog) мы перегрузили метод MakeSound(int volume), и теперь у него есть обе версии: с параметром и без.

10. Типичные ошибки при перегрузке методов

Ошибка №1: попытка перегрузить метод только по возвращаемому типу.
Это невозможно — возвращаемый тип не входит в сигнатуру метода. Перегрузка должна отличаться по количеству или типам входных параметров, а не по void или int.

Ошибка №2: неоднозначные перегрузки, сбивающие компилятор.
Перегрузки с одинаковым числом параметров и близкими типами (например, int и double) могут запутать компилятор. Пример: Print(int a, double b) и Print(double a, int b) — вызов Print(1, 1) вызовет ошибку неоднозначности.

Ошибка №3: конфликт params с другими перегрузками.
Метод с params может перехватить вызов, предназначенный для другой перегрузки. Если типы совпадают, компилятор может выбрать не тот метод, что вы ожидали.

Ошибка №4: забыли, что ref и out входят в сигнатуру.
Методы Do(ref int x) и Do(out int x) считаются разными перегрузками. Если не учитывать это, легко запутаться и вызвать неправильную версию метода.

2
Задача
C# SELF, 21 уровень, 1 лекция
Недоступна
Создание перегруженных методов для вычисления площади фигур
Создание перегруженных методов для вычисления площади фигур
2
Задача
C# SELF, 21 уровень, 1 лекция
Недоступна
Метод для форматированного вывода данных
Метод для форматированного вывода данных
Комментарии (7)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Александр Уровень 24
12 января 2026
читайте не ТЗ, а требования. Всё проходит.

public class Shape
{
    // Метод для вычисления площади круга
    public double CalculateArea(double radius)
    {
        return Math.PI * radius * radius;
    }

    // Метод для вычисления площади прямоугольника
    public double CalculateArea(double length, double width)
    {
        return length * width;
    }

    // Метод для вычисления площади треугольника
    public double CalculateArea(double sideA, double sideB, double sideC)
    {
        double p = (sideA + sideB + sideC) / 2;
        return Math.Sqrt(p * (p - sideA) * (p - sideB) * (p - sideC));
    }
}
Yurii N Уровень 50
10 января 2026
Эту шляпу до сих пор не починили )
Anonymous #3396857 Уровень 22
9 января 2026
Даже "Правильное решение" в задаче вычисление площади фигур не проходит проверку!
Aleksei Perchukov Уровень 66
20 августа 2025
ПОЧИНИТЕ ВАЛИДАТОР В ЗАДАЧЕ "Создание перегруженных методов для вычисления площади фигур"
Дмитрий Уровень 60
3 сентября 2025
Валидатор проверяет задачу согласно ТЗ (и не важно, что она не компилируется, т.к. сигнатура для квадрата и круга одинаковая)
Николай Уровень 28
8 октября 2025
Я не знаю как решали эту задачу до меня, но кажется валидатор окончательно сломался и не принимает никакое решение)))
Ilya Уровень 32
8 декабря 2025
что-то походу мы бетатестим курс этот... Да, эта задача теперь нерешаемая 😢