Перегрузка арифметических операторов
Определяйте +, -, * для собственных типов.
«Перегрузка арифметических операторов» — бесплатный урок C# Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.
Зачем перегружать арифметические операторы
Перегрузка операторов позволяет использовать в собственных типах привычные символы, такие как +, - и *. Для типов, подобных значениям, например векторов, денег или комплексных чисел, это делает код похожим на математические формулы, а не на вызовы методов.
Синтаксис оператора +
Перегруженный оператор объявляется как метод public static, имя которого состоит из слова operator и следующего за ним символа. По крайней мере один параметр должен иметь тип содержащего метода типа.
using System;
public struct Vector2
{
public int X, Y;
public Vector2(int x, int y) { X = x; Y = y; }
public static Vector2 operator +(Vector2 a, Vector2 b)
=> new Vector2(a.X + b.X, a.Y + b.Y);
public override string ToString() => "(" + X + ", " + Y + ")";
}
public class Program
{
public static void Main()
{
var sum = new Vector2(1, 2) + new Vector2(3, 4);
Console.WriteLine(sum);
}
}Вычитание и умножение
Вы можете перегрузить несколько операторов для одного типа. Здесь мы добавляем к нашему вектору вычитание и умножение на скаляр.
using System;
public struct Vector2
{
public int X, Y;
public Vector2(int x, int y) { X = x; Y = y; }
public static Vector2 operator -(Vector2 a, Vector2 b)
=> new Vector2(a.X - b.X, a.Y - b.Y);
public static Vector2 operator *(Vector2 a, int k)
=> new Vector2(a.X * k, a.Y * k);
public override string ToString() => "(" + X + ", " + Y + ")";
}
public class Program
{
public static void Main()
{
var v = new Vector2(5, 6) - new Vector2(2, 1);
Console.WriteLine(v);
Console.WriteLine(new Vector2(2, 3) * 4);
}
}Операторы всегда статические
Перегруженные операторы должны быть static. Они не работают со скрытым this; вместо этого операнды передаются как явные параметры. Компилятор сопоставляет символ с методом.
using System;
public struct Money
{
public decimal Amount;
public Money(decimal amount) { Amount = amount; }
public static Money operator +(Money a, Money b)
=> new Money(a.Amount + b.Amount);
public override string ToString() => "$" + Amount;
}
public class Program
{
public static void Main()
{
var total = new Money(10.5m) + new Money(4.25m);
Console.WriteLine(total);
}
}Унарные операторы
Унарные операторы, такие как отрицание, принимают один операнд. Перегрузите operator - с одним параметром, чтобы поддержать выражения вроде -v.
using System;
public struct Vector2
{
public int X, Y;
public Vector2(int x, int y) { X = x; Y = y; }
public static Vector2 operator -(Vector2 a)
=> new Vector2(-a.X, -a.Y);
public override string ToString() => "(" + X + ", " + Y + ")";
}
public class Program
{
public static void Main()
{
Console.WriteLine(-new Vector2(3, -7));
}
}Операнды разных типов
Один из операндов может иметь другой тип. Реализация обоих порядков позволяет пользователям естественно записывать выражение в любом варианте.
using System;
public struct Temperature
{
public double Celsius;
public Temperature(double c) { Celsius = c; }
public static Temperature operator +(Temperature t, double delta)
=> new Temperature(t.Celsius + delta);
public static Temperature operator +(double delta, Temperature t)
=> new Temperature(t.Celsius + delta);
public override string ToString() => Celsius + "C";
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Temperature(20) + 5);
Console.WriteLine(5 + new Temperature(20));
}
}Возврат новых значений
Арифметические операторы не должны изменять свои операнды. Они вычисляют и возвращают новое значение, оставляя исходные значения неизменными, как это делает int.
using System;
public struct Vector2
{
public int X, Y;
public Vector2(int x, int y) { X = x; Y = y; }
public static Vector2 operator +(Vector2 a, Vector2 b)
=> new Vector2(a.X + b.X, a.Y + b.Y);
public override string ToString() => "(" + X + ", " + Y + ")";
}
public class Program
{
public static void Main()
{
var a = new Vector2(1, 1);
var b = new Vector2(2, 2);
var c = a + b;
Console.WriteLine("a unchanged: " + a);
Console.WriteLine("result: " + c);
}
}Цепочки арифметических операций
Поскольку каждый оператор возвращает тот же тип, выражения естественно объединяются в цепочки и соблюдают обычные правила приоритета и ассоциативности.
using System;
public struct Vector2
{
public int X, Y;
public Vector2(int x, int y) { X = x; Y = y; }
public static Vector2 operator +(Vector2 a, Vector2 b) => new Vector2(a.X + b.X, a.Y + b.Y);
public static Vector2 operator *(Vector2 a, int k) => new Vector2(a.X * k, a.Y * k);
public override string ToString() => "(" + X + ", " + Y + ")";
}
public class Program
{
public static void Main()
{
var result = new Vector2(1, 1) + new Vector2(2, 2) * 3;
Console.WriteLine(result);
}
}Операторы в классах
Перегрузка операторов работает и в классах, а не только в структурах. Учитывайте значение null: операнд класса может быть равен null, поэтому при необходимости добавьте проверку.
using System;
public class Complex
{
public double Re, Im;
public Complex(double re, double im) { Re = re; Im = im; }
public static Complex operator +(Complex a, Complex b)
=> new Complex(a.Re + b.Re, a.Im + b.Im);
public override string ToString() => Re + " + " + Im + "i";
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Complex(1, 2) + new Complex(3, 4));
}
}Полноценный числовой тип
Здесь показан небольшой тип дроби со сложением. Он демонстрирует, как перегрузка превращает предметный тип в объект, который ведёт себя подобно встроенному числу.
using System;
public struct Fraction
{
public int Num, Den;
public Fraction(int num, int den) { Num = num; Den = den; }
public static Fraction operator +(Fraction a, Fraction b)
=> new Fraction(a.Num * b.Den + b.Num * a.Den, a.Den * b.Den);
public override string ToString() => Num + "/" + Den;
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Fraction(1, 2) + new Fraction(1, 3));
}
}Попробуйте сами
Добавьте в структуру, представляющую деньги, сложение и умножение на скаляр, а затем составьте выражение, которое выглядит как обычная арифметика.
using System;
public struct Money
{
public decimal Amount;
public Money(decimal a) { Amount = a; }
public static Money operator +(Money a, Money b) => new Money(a.Amount + b.Amount);
public static Money operator *(Money a, int qty) => new Money(a.Amount * qty);
public override string ToString() => "$" + Amount;
}
public class Program
{
public static void Main()
{
var price = new Money(4.50m);
var total = price * 3 + new Money(2.00m);
Console.WriteLine(total);
}
}Быстрая проверка
Вспомните сигнатуру перегруженного оператора.
Итоги
Перегрузка арифметических операторов позволяет типам, подобным значениям, выглядеть как математические выражения.
- Объявляйте их с помощью
public staticи ключевого словаoperator. - По крайней мере один параметр должен иметь тип содержащего типа.
- Возвращайте новое значение и никогда не изменяйте операнды.
- Для арифметики с разными типами предусмотрите оба порядка операндов.
Часто задаваемые вопросы
Урок «Перегрузка арифметических операторов» бесплатный?
Да — полный текст урока «Перегрузка арифметических операторов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.
Чему я научусь в уроке «Перегрузка арифметических операторов»?
Определяйте +, -, * для собственных типов. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C# Academy?
Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Перегрузка арифметических операторов»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C# Academy?
Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Перегрузка арифметических операторов
- Перегрузка операторов сравнения
- Пользовательские преобразования
- Рекомендации по перегрузке операторов