Введение

Наряду с методами в классах и структурах мы можем также определять операторы.

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

Перегрузка операторов позволяет реализовать удобный синтаксис для работы с классами в программировании. Эта возможность является одним из ключевых преимуществ объектно-ориентированного программирования на C#.

Перегрузка операторов С# делает код красивее. Мы задаем, редактируем, или сами можем придумывать поведение определенного нами класса. Используя унарные, бинарные операторы, операторы сравнения и логические операторы мы задаем определенное действие компилятору.

Перегружены могут быть следующие операторы:

+ - * / ++ -- ! ~ % & | ^ == != < << >> >

Синтаксис

// перегрузка унарного оператора public static тип operator primer(тип_параметра операнд)
{
// запросы
}

// перегрузка бинарного оператора public static тип operator primer (тип_параметра1 операнд1, тип_параметра1 операнд2)
{
// запросы
}

Метод объявляется модификаторами public и static. Оператор, который перегружается должен быть одного типа с операндами.

Пример

Давайте разберем перегрузку операторов на примере, который предлагает официальная документация языка программирования C#

Рис.1 Примера кода реализации перегрузки операторов
Рис.1 Примера кода реализации перегрузки операторов

Разбор кода

Думаю на первый взгляд пример, который дает официальная документации очень сложный и не понятный. Чтобы внести ясность разберем его постепенно - шаг за шагом.

Шаг 1: Создадим структуру Fraction

Данная структура будет представлять собой дробь. Соответственно у нее будут: числитель, знаменатель в виде полей и конструктор, для передачи значений в эти поля. (Рис.2)

Рис.2 Объявление структуры Fraction (дробь)
Рис.2 Объявление структуры Fraction (дробь)

Шаг 2: Переопределим метод ToString() у данной структуры, что получать при вызове методы вывод дроби удобный для понимания. (Рис.3)

Рис.3 Перегрузка метода ToString()
Рис.3 Перегрузка метода ToString()

Исходя из данного кода , при вызове метода у объекта структуры мы получим строку вида числитель/знаменатель

public override string ToString() => $"{num} / {den}"; // перегрузка метода

Шаг 3: Перегрузим оператор `+` (Рис.4)

Перегрузка оператора не сложения, а указания на положительность дроби

Рис.4 Перегрузка оператора +
Рис.4 Перегрузка оператора +
public static Fraction operator +(Fraction a) => a;

Шаг 4: Перегрузим оператор `-`, который сделает дробь отрицательной (Рис.5)

Рис.5 Перегрузка оператора -
Рис.5 Перегрузка оператора -
public static Fraction operator -(Fraction a) => new Fraction(-a.num, a.den);

Шаг 5: Перегрузка оператора сложения (Рис.6)

В данном случае мы перегружаем бинарный оператор, он принимает две дроби (A и B), и в результате возвращает новую дробь, которая будет являться результатом сложения двух дробей

Рис.6 Перегрузка оператора сложения
Рис.6 Перегрузка оператора сложения
public static Fraction operator +(Fraction a, Fraction b) => new Fraction(a.num * b.den + b.num * a.den, a.den * b.den);

Шаг 6: Перегрузка оператора вычитания (Рис.7)

В данном случае мы перегружаем бинарный оператор, он принимает две дроби (A и B), и в результате возвращает новую дробь, которая будет являться результатом вычитания двух дробей

Рис.7 Перегрузка оператора вычитания
Рис.7 Перегрузка оператора вычитания
public static Fraction operator -(Fraction a, Fraction b) => a + (-b);

Шаг 7: Перегрузка оператора вычитания (Рис.8)

В данном случае мы перегружаем бинарный оператор, он принимает две дроби (A и B), и в результате возвращает новую дробь, которая будет являться результатом умножения двух дробей

Рис.8 Перегрузка оператора умножения
Рис.8 Перегрузка оператора умножения
public static Fraction operator *(Fraction a, Fraction b) => new Fraction(a.num * b.num, a.den * b.den);

Шаг 8: Перегрузка оператора вычитания (Рис.9)

В данном случае мы перегружаем бинарный оператор, он принимает две дроби (A и B), и в результате возвращает новую дробь, которая будет являться результатом деления двух дробей

Рис.9 Перегрузка оператора деления
Рис.9 Перегрузка оператора деления
public static Fraction operator /(Fraction a, Fraction b)
{
    if (b.num == 0)
    {

      throw new DivideByZeroException();
    }
    return new Fraction(a.num * b.den, a.den * b.num);
}

Шаг 9: Теперь мы можем использовать операторы + - * / для нашей структуры Fraction и для них будет выполнять логика описанная в перегрузке. Грубо говоря мы сказали компилятору , то как выглядят различные виды операций (математических) для нашей структры. (Рис.10)

Рис.10 использование
Рис.10 использование
var a = new Fraction(5, 4);

var b = new Fraction(1, 2);

Console.WriteLine(-a); // output: -5 / 4

Console.WriteLine(a + b); // output: 14 / 8

Console.WriteLine(a - b); // output: 6 / 8

Console.WriteLine(a * b); // output: 5 / 8

Console.WriteLine(a / b); // output: 10 / 4

Перегрузка операторов C# заключение

Важно помнить, что на перегрузку операторов есть ограничения. Нельзя использовать оператор присваивания =. Кроме них есть операторы, которые в языке С# еще не определены. Так же, нельзя изменить количество операндов. Для бинарных операторов нельзя задавать три аргумента. Поскольку в его синтаксисе указан только два аргумента.

Чтобы создать легкий интерфейс, важно использовать перегрузки операторов. К тому же, учитывая их, вы упрощаете набранный код программы. Данное действие над операторами интересно тем, что пользователь сможет внедрить в программу свои правила и требования, контролируя функции операторов.

Комментарии (0)