Перегрузка методов, операторов и конструкторов в C#: 4‑я часть гайда по ООП
C# позволяет использовать один метод для разных типов данных и даже переопределить логику операторов. Разбираемся в перегрузках.
vlada_maestro / shutterstock
Перегрузка методов класса C# — один из мощнейших механизмов языка, который позволяет определить несколько методов с одним и тем же именем, но с различными параметрами. Кроме того, в C# по схожему принципу можно перегружать операторы и конструкторы. Такой подход делает код более гибким и понятным, и в четвёртой статье цикла про ООП мы поговорим о нём подробно.
Все статьи про ООП
Перегрузка методов
C# — строго типизированный язык. Это значит, что вы не можете поместить строку в переменную типа int — сначала нужно провести преобразование. Так же и в метод нельзя передать параметр типа float, если при объявлении метода был указан тип double.
Однако если вы экспериментировали с методом WriteLine () класса Console, то могли заметить, что в него можно передавать аргументы разных типов:
Кажется, что нарушена типизация, но компилятор не выдаёт ошибку. Вместо этого всё успешно выводится на экран:
Так происходит потому, что у метода WriteLine () есть перегрузки — методы с таким же названием, но принимающие другие аргументы:
Когда вы вызовете метод Sum (), компилятор по переданным аргументам узнает, какую из его перегрузок вы имели в виду — так же, как это происходит с методом WriteLine ().
При этом стоит учитывать, что значение имеют только типы и количество передаваемых аргументов. Например, можно написать такие перегрузки:
У этих методов одинаковые параметры, но разный возвращаемый тип. Попытка скомпилировать такой код приведёт к ошибке — так же, как и создание перегрузки с такими же аргументами, но с другими названиями:
Перегрузка конструкторов
То же самое можно сделать и с конструкторами классов:
Альтернатива этому решению — указать значения для аргументов по умолчанию:
Несмотря на, то что здесь меньше кода, на мой взгляд, это может запутать. Потому что придётся каждый раз заполнять все значения, даже если нужен только один аргумент из конца списка. Перегрузка же позволяет определить и порядок параметров (если они разных типов).
Перегрузка операторов
Перегрузить можно даже операторы, то есть:
- +,
- ++,
- -,
- --,
- *,
- /,
- ==,
- >,
- <,
- >=,
- <=.
Для этого в определении класса нужно добавить вот такую конструкцию:
Так как использоваться этот оператор должен без объявления экземпляра класса (item1 + item2, а не item1 item1.+ item2), то указываются модификаторы public static.
Например, мы хотим улучшать предметы в играх. Во многих MMO1 популярна механика, когда один предмет улучшается за счёт другого. Мы можем сделать это с помощью перегрузки оператора сложения:
Теперь при сложении двух объектов класса Item мы будем получать третий объект с улучшенными параметрами. Вот пример использования такого оператора:
В результате в консоль будет выведено следующее:
Перегрузка операторов преобразования типов
Хотя типизация в C# строгая, типы можно преобразовывать. Например, мы можем конвертировать число типа float в число типа int:
С помощью перегрузки операторов преобразования типов мы можем прописать любую логику для конвертации объектов. Для наглядности создадим класс Hero:
В этом классе хранятся данные о персонаже. В MMO часто можно увидеть такой параметр, как мощь — это сумма всех характеристик героя или предмета. Например, её можно посчитать по следующей формуле:
Мощь = (сила + ловкость + интеллект) * уровень.
Мы можем использовать преобразование типов, чтобы автоматически переводить объект в его мощь. Для этого нужно использовать такую конструкцию.
Модификатор implicit говорит компилятору, что преобразование может быть неявным. То есть оно сработает, если написать так:
Explicit, наоборот, означает, что преобразование должно быть явным:
Вот как будет выглядеть перегрузка преобразования объекта класса Hero в int:
Вот как она будет использоваться:
Вывод в консоль будет следующим:
Проблемы читаемости
Несмотря на то, что перегрузки помогают быстро реализовать какой-нибудь функционал, они могут навредить читаемости. Например, не всегда можно сразу понять, зачем в коде складываются два объекта.
Или же непонятно, зачем конвертировать Hero в int. Ясность вносит название переменной (power), но этого недостаточно.
В большинстве случаев лучше использовать более простые решения. Например, можно создать для объекта свойство Power, которое возвращает сумму характеристик.
Вместо сложения объектов можно написать метод Enhance (), который будет принимать другой предмет и прибавлять его характеристики к текущему.
Такие перегрузки стоит использовать либо если вы работаете над кодом один, либо если есть подробная документация.
Домашнее задание
Создайте игру, в которой можно улучшать одни предметы с помощью других. При улучшении предмету добавляется опыт. Когда его станет достаточно, необходимо повысить уровень. Количество опыта должно зависеть от мощи.
Заключение
Полиморфизм — очень удобный инструмент. Однако в этой статье была затронута лишь его часть; чтобы начать работать со второй, нужно ознакомиться с принципами наследования и абстракции.
Больше интересного про код в нашем телеграм-канале. Подписывайтесь!