Перегрузка операторов — предопределенные унарные, арифметические операторы, операторы равенства и сравнения

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

Для объявления оператора используйте ключевое слово operator. Объявление оператора должно соответствовать следующим правилам:

  • Оно должно включать public и модификатор static.
  • У унарного оператора один входной параметр. У бинарного оператора два входных параметра. В каждом случае хотя бы один параметр должен иметь тип T или T?, где T — тип, который содержит объявление оператора.

В следующем примере определяется упрощенная структура, представляющая рациональное число. Структура перегружает некоторые арифметические операторы:

public readonly struct Fraction
{
    private readonly int num;
    private readonly int den;

    public Fraction(int numerator, int denominator)
    {
        if (denominator == 0)
        {
            throw new ArgumentException("Denominator cannot be zero.", nameof(denominator));
        }
        num = numerator;
        den = denominator;
    }

    public static Fraction operator +(Fraction a) => a;
    public static Fraction operator -(Fraction a) => new Fraction(-a.num, a.den);

    public static Fraction operator +(Fraction a, Fraction b)
        => new Fraction(a.num * b.den + b.num * a.den, a.den * b.den);

    public static Fraction operator -(Fraction a, Fraction b)
        => a + (-b);

    public static Fraction operator *(Fraction a, Fraction b)
        => new Fraction(a.num * b.num, a.den * b.den);

    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);
    }

    public override string ToString() => $"{num} / {den}";
}

public static class OperatorOverloading
{
    public static void Main()
    {
        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
    }
}

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

Можно также использовать ключевое слово operator для определения пользовательского преобразования типа. Дополнительные сведения см. в разделе Операторы пользовательского преобразования.

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

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

Операторы Примечания
+x, -x, !x, ~x, ++, --, true, false Операторы true и false должны быть перегружены вместе.
x + y, x - y, x * y, x / y, x % y,
x & y, x | y, x ^ y,
x << y, x >> y, x >>> y
x == y, x != y, x < y, x > y, x <= y, x >= y Должен быть перегружен парами следующим образом: == и !=, < и >, <= и >=.

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

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

Операторы Альтернативные варианты
x && y, x || y Перегрузка операторов true и и false операторов & или | . Дополнительные сведения см. в разделе Пользовательские условные логические операторы.
a[i], a?[i] Определите индексатор.
(T)x Определите преобразования пользовательских типов, которые могут выполняться выражением приведения. Дополнительные сведения см. в разделе Операторы пользовательского преобразования.
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, >>>= Перегрузка соответствующего двоичного оператора. Например, при перегрузке двоичного + оператора += неявно перегружается.
^x, x = y, x.y, x?.y, c ? t : f, x ?? y, ??= y,
x..y, x->y, =>, f(x), as, await, checked, unchecked, default, delegate, is, nameof, new,
sizeof, stackalloc, switch, typeof, with
Нет.

Спецификация языка C#

Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:

См. также