Перегрузка операторов C# (Operator overloading)

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

Подпишись на группу Вконтакте и Телеграм-канал. Там еще больше полезного контента для программистов.
А на YouTube-канале ты найдешь обучающие видео по программированию. Подписывайся!

Перегрузка операторов в языке программирования C#

Перегрузка операций в С# похожа на переопределение методов. В языке С# в зависимости от типа оператора объявляется оно двумя способами.

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

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

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

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

В С# существует операторы «+», «-», «!», «==», «!=» и другие, которые предназначены для работы с типами данных.

Так как в языке программирования С# используются готовые алгоритмы базовых операций, в некоторых моментах важна перегрузка операторов. Например, когда используем оператор + для целых чисел он возвращает сумму чисел, а если использовать его для строковых типов данных тогда выполняется объединение двух строк.

string a = "Сергей "; 
string b = "Сергеев";
string c = a + b; //результат "Сергей Сергеев" 

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

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

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

Например, есть класс «точки» с координатами х и у. Два целых числа, объединенные одним классом. Мы можем сложить эти две точки. Даже если компилятор умный, система не в состоянии понять какое сложение точек выполнить. Поэтому нужно перегружать оператор, чтобы объяснить компилятору, как системе себя вести и какое действие выполнить. Возможно системе нужно сложить между собой все х или же сложить все y. Компилятор может выполнить банальное сложение двух заданных точек, но, чтобы их выполнить, нужно указать поведение: например, когда нужно решать по формуле, для этого и служит перегрузка операторов. При ней пользователь С# задает правильное поведение, которое ожидается от класса.

class MyPoint 
{
  int х, у,z// три координаты
  public MyPoint() { х = у = z = 0; }

  // Перегрузить бинарный оператор +.
  public static MyPoint operator +(MyPoint op1, MyPoint op2)
  {
    MyPoint result = new MyPoint();
    /* Сложить координаты двух точек и возвратить результат. */
    result.х = op1.x + ор2.х; // Эти операторы выполняют
    result.у = op1.y + ор2.у; // целочисленное сложение,
    result.z = op1.z + op2.z; // сохраняя свое исходное назначение.
    return result;
  }

  // Перегрузить бинарный оператор -.
  public static MyPoint1 operator -(MyPoint1 op1, MyPoint1 op2)    
  {
    MyPoint1 result = new MyPoint1();
    /* Обратите внимание на порядок следования операндов:
    op1 — левый операнд, а ор2 — правый операнд. */
    result.х = op1.x - ор2.х; // Эти операторы
    result.у = op1.y - ор2.у; // выполняют целочисленное
    result.z = op1.z - op2.z; // вычитание
    return result;
  }

  // Вывести координаты X, Y, Z.
  public void Show()
  {
    Console.WriteLine(x + ", " + у + ", " + z);
  }
}

Когда оператор перегружается, выполняет заданные поведение. Но его первоначальное назначение не меняется.

Перегружаемые операторы

Эти операторы можно перегрузить:

  1. Унарные операции +,  -,  !,  ++, — true, false;
  2. Бинарные операции +,  -,  *,  /,  %,  &,  |,  ,<<,  >>;
  3. Операции сравнения должны быть перегружены парами ==,  !=,<,  >,<=, >=.

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

// Перегрузить оператор >.
public static bool operator >(dot op1, dot op2)
{
  if(op1.val > op2.val) return true;
  else return false;
}

// Перегрузить оператор <.
public static bool operator <( dot op1, dot op2)
{
  if(op1.val < op2.val) return true;
  else return false;
}

Еще один пример для перегрузки операторов ==, -, *= приведен ниже. В качестве класса выберем «квадратное уравнение» с коэффициентами.

 class KvadratUravn
 {
     public KvadratUravn ():this(0, 0, 0)
     {
     }
     public KvadratUravn (double a_, double b_, double c_)
     {
         a=a_;
         b=b_;
         c=c_;
     }
     public double A { get { return a; } set { a = value; } }
     public double B { get { return b; } set { b = value; } }
     public double C { get { return c; } set { c = value; } }
 
 
     public static bool operator ==( KvadratUravn raz, KvadratUravn dva)
     {
         return raz.a == dva.a &&
             raz.b == dva.b &&
             raz.c == dva.c;
     }
 
     public static bool operator !=( KvadratUravn raz, KvadratUravn dva)
     {
         return raz.a != dva.a &&
             raz.b != dva.b &&
             raz.c != dva.c;
     }
 
     public static KvadratUravn operator *( KvadratUravn raz, double dva)
     {
         return new KvadratUravn (raz.a * dva,
             raz.b * dva,
             raz.c * dva);
     }
 
     public static KvadratUravn operator -( KvadratUravn raz, double dva)
     {
         return new KvadratUravn (raz.a - dva,
             raz.b - dva,
             raz.c - dva);
     }
     public override string ToString()
     {
         return string.Format("{0}, {1}, {2}", a, b, c);
     }
     private double a;
     private double b;
     private double c;
 };
 
 class Program
 {
     static void Main(string[] args)
     {
         KvadratUravn expr = new KvadratUravn (1, 2, 3);
            Console.WriteLine(expr.ToString());
         expr *= 5;
            Console.WriteLine(expr.ToString());
         expr -= 10;
            Console.WriteLine(expr.ToString());
     }
 }

В следующем фрагменте кода программы приведен пример перегрузки логических операторов !, & и | для объектов класса Dot. Если один из точек координаты не равно нулю тогда программе покажет истину, а если все координаты равны нулю, тогда программа выдает значение ложь.

 // Класс для хранения координат.
class dot
{
  int х, у, z; // трехмерные координаты
  public dot () { х = у = z = 0; }
  public static bool operator |(dot op1, dot op2)
  {
    if( ((op1.x != 0) || (op1.у != 0) || (op1.z != 0)) | ((op2.x != 0) || (op2.у != 0) || (op2.z != 0)) )
      return true;
    else
      return false;
  }

  // Перегрузить логический оператор &.
  public static bool operator &(dot op1, dot op2)  
  {
    if( ((op1.x != 0) && (op1.у != 0) && (op1.z != 0)) & ((op2.x != 0) && (op2.y != 0) && (op2.z != 0)) )
      return true;
    else
      return false;
  }

  // Перегрузить логический оператор !.
  public static bool operator !(dot op)
  {
    if((op.x != 0) || (op.y != 0) || (op.z != 0))
      return false;
    else return true;
  }

  // Вывести координаты X, Y, Z.
  public void Show()
  {
    Console.WriteLine(x + ", " + у + ", " + z);
  }
}

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

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

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

Также рекомендую прочитать статью Override C# | Переопределение методов C#. А также подписывайтесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для программистов.