Поделиться через


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

Определяемый пользователем тип может перегружать предопределенный оператор 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++--truefalse false Операторы true должны быть перегружены вместе.
x + y, , x - yx / yx * yx % y,
x & y, , x | yx ^ y
x << y, , x >> yx >>> y
x == y, , x != yx > yx < yx <= y,x >= y Должен быть перегружен в парах следующим образом: == и , < а !=также >. <=>=

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

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

Операторы Альтернативные варианты
x && y, x || y Перегрузите операторы true и false& операторы или | операторы. Дополнительные сведения см. в разделе "Определяемые пользователем условные логические операторы".
a[i], a?[i] Определите индексатор.
(T)x Определите преобразования пользовательских типов, которые могут выполняться выражением приведения. Дополнительные сведения см. в разделе Операторы пользовательского преобразования.
+=, -=, *=/=%=&=|=^=<<=>>=>>>= Перегрузите соответствующий двоичный оператор. Например, при перегрузке двоичного + оператора += неявно перегружен.
^x, x = y, x.yx?.yc ? t : fx ?? y??= y
x..y, x->y=>f(x)asawaitcheckeduncheckeddefaultdelegateisnameofnew
sizeof, , stackallocswitch, typeofwith
Нет.

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

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

См. также