Przeciążanie operatorów — wstępnie zdefiniowane jednoargumentowe, arytmetyczne, równości i operatory porównania

Typ zdefiniowany przez użytkownika może przeciążać wstępnie zdefiniowany operator języka C#. Oznacza to, że typ może zapewnić niestandardową implementację operacji w przypadku, gdy jeden lub oba operandy są tego typu. Sekcja Przeciążenia operatorów pokazuje, które operatory języka C# mogą być przeciążone.

Użyj słowa kluczowego operator , aby zadeklarować operator. Deklaracja operatora musi spełniać następujące reguły:

  • Zawiera zarówno modyfikator, jak publicstatic i .
  • Operator jednoargumentowy ma jeden parametr wejściowy. Operator binarny ma dwa parametry wejściowe. W każdym przypadku co najmniej jeden parametr musi mieć typ T lub T? gdzie T jest typem zawierającym deklarację operatora.

W poniższym przykładzie zdefiniowano uproszczoną strukturę reprezentującą liczbę racjonalną. Struktura przeciąża niektóre operatory arytmetyczne:

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

Powyższy przykład można rozszerzyć, definiując niejawną konwersję z int na Fraction. Następnie przeciążone operatory obsługują argumenty tych dwóch typów. Oznacza to, że możliwe byłoby dodanie liczby całkowitej do ułamka i uzyskanie ułamka w wyniku.

Słowo kluczowe służy operator również do definiowania konwersji typu niestandardowego. Aby uzyskać więcej informacji, zobacz Operatory konwersji zdefiniowane przez użytkownika.

Operatory przeciążalne

W poniższej tabeli przedstawiono operatory, które mogą być przeciążone:

Operatory Uwagi
+x, -x, , !x, ++~x, , --, , truefalse Operatory true i false muszą być ze sobą przeciążone.
x + y, , x - y, x * y, x / y, , x % y
x & y, , x | y, , x ^ y
x << y, , x >> yx >>> y
x == y, , x != y, x < y, x > y, , x <= yx >= y Muszą być przeciążone w parach w następujący sposób: == i !=, < i >.>=<=

Nie przeciążalne operatory

W poniższej tabeli przedstawiono operatory, których nie można przeciążyć:

Operatory Alternatywy
x && y, x || y Przeciąż operatory true i oraz false& operatory lub | . Aby uzyskać więcej informacji, zobacz Operatory logiczne warunkowe zdefiniowane przez użytkownika.
a[i], a?[i] Zdefiniuj indeksator.
(T)x Zdefiniuj konwersje typów niestandardowych, które mogą być wykonywane przez wyrażenie rzutowane. Aby uzyskać więcej informacji, zobacz Operatory konwersji zdefiniowane przez użytkownika.
+=, -=, , , %=^=>>=/=&=|=<<=*=>>>= Przeciąż odpowiedniego operatora binarnego. Na przykład podczas przeciążenia operatora += binarnego + jest niejawnie przeciążony.
^x, x = y, , x.y, c ? t : fx?.y, , x ?? y, , ??= y
x..y, x->y, , , asawaitnameoff(x)uncheckednewcheckeddefaultdelegateis=>
sizeof, , stackalloc, switch, , typeofwith
Brak.

specyfikacja języka C#

Aby uzyskać więcej informacji, zobacz następujące sekcje specyfikacji języka C#:

Zobacz też