Megosztás a következőn keresztül:


Operátorok túlterhelése – előre definiált, nem meghatározott, számtani, egyenlőségi és összehasonlító operátorok

A felhasználó által definiált típus túlterhelhet egy előre definiált C# operátort. Ez azt jelzi, hogy egy típus lehetővé teheti egy művelet egyéni implementálását abban az esetben, ha az egyik vagy mindkét operandus ilyen típusú. A Túlterhelhető operátorok szakasz azt mutatja be, hogy mely C#-operátorok terhelhetők túl.

operator A kulcsszó használatával deklarálhat egy operátort. Az operátor-deklarációnak meg kell felelnie a következő szabályoknak:

  • Ez tartalmaz egy public módosító.
  • A nem kötelező operátorok egyetlen bemeneti paraméterrel rendelkeznek. A bináris operátor két bemeneti paraméterrel rendelkezik. Minden esetben legalább egy paraméternek típusú T vagy T? kell lennie, ahol T az operátor deklarációt tartalmazó típus.
  • Tartalmazza a static módosító, kivéve az összetett hozzárendelési operátorok, például +=.
  • Az inkrement (++) és dekrement (--) operátorok statikus vagy példánymetódusként is implementálhatók. A példánymetódus-operátorok a C# 14-ben bevezetett új funkciók.

Az alábbi példa egy egyszerűsített struktúrát határoz meg, amely egy racionális számot jelöl. A struktúra túlterheli az aritmetikai operátorok némelyikét:

public struct Fraction
{
    private int numerator;
    private int denominator;

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

    public static Fraction operator +(Fraction operand) => operand;
    public static Fraction operator -(Fraction operand) => new Fraction(-operand.numerator, operand.denominator);

    public static Fraction operator +(Fraction left, Fraction right)
        => new Fraction(left.numerator * right.denominator + right.numerator * left.denominator, left.denominator * right.denominator);

    public static Fraction operator -(Fraction left, Fraction right)
        => left + (-right);

    public static Fraction operator *(Fraction left, Fraction right)
        => new Fraction(left.numerator * right.numerator, left.denominator * right.denominator);

    public static Fraction operator /(Fraction left, Fraction right)
    {
        if (right.numerator == 0)
        {
            throw new DivideByZeroException();
        }
        return new Fraction(left.numerator * right.denominator, left.denominator * right.numerator);
    }

    // Define increment and decrement to add 1/den, rather than 1/1.
    public static Fraction operator ++(Fraction operand)
        => new Fraction(operand.numerator + 1, operand.denominator);

    public static Fraction operator --(Fraction operand) =>
        new Fraction(operand.numerator - 1, operand.denominator);

    public override string ToString() => $"{numerator} / {denominator}";

    // New operators allowed in C# 14:
    public void operator +=(Fraction operand) =>
        (numerator, denominator ) =
        (
            numerator * operand.denominator + operand.numerator * denominator,
            denominator * operand.denominator
        );

    public void operator -=(Fraction operand) =>
        (numerator, denominator) =
        (
            numerator * operand.denominator - operand.numerator * denominator,
            denominator * operand.denominator
        );

    public void operator *=(Fraction operand) =>
        (numerator, denominator) =
        (
            numerator * operand.numerator,
            denominator * operand.denominator
        );

    public void operator /=(Fraction operand)
    {
        if (operand.numerator == 0)
        {
            throw new DivideByZeroException();
        }
        (numerator, denominator) =
        (
            numerator * operand.denominator,
            denominator * operand.numerator
        );
    }

    public void operator ++() => numerator++;

    public void operator --() => numerator--;
}

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

Az előző példát kiterjesztheti úgy, hogy implicit konverziót határoz megint-ről Fraction-re. Ezután a túlterhelt operátorok támogatnák a két típus argumentumait. Ez azt jelenti, hogy egy egész számot adhat hozzá egy törthöz, és ennek eredményeként egy törtet kaphat.

A kulcsszóval operator egyéni típuskonvertálást is definiálhat. További információ: Felhasználó által definiált konverziós operátorok.

Túlterhelhető operátorok

Az alábbi táblázat a túlterhelhető operátorokat mutatja be:

Működtetők Jegyzetek
+x, -x, !x, ~x++, --, truefalse Az true és false operátort együtt kell túlterhelni.
x + y, x - y, x * y, x / yx % y
x & y, x | y, x ^ y
\, \, \
x == y, x != y, x < y, x > yx <= yx >= y A következő párokban kell túlterhelni: == és !=, < és >, <= és >=.
+=, -=, *=, /=, %=&=, \|=, ^=, <<=, , >>=>>>= Az összetett hozzárendelési operátorok túlterhelhetők a C# 14-ben és újabb verzióiban.

Az összetett hozzárendelés túlterhelt operátorának az alábbi szabályokat kell követnie:

  • A módosítónak public tartalmaznia kell.
  • Nem tartalmazhatja a static módosítót.
  • A visszatérési típusnak meg kell lennie void.
  • A deklarációnak tartalmaznia kell egy paramétert, amely az összetett hozzárendelés jobb oldalát jelöli.

A C# 14 verziótól kezdve a növekmény- és csökkenésoperátorok példánytagokként túlterhelhetők. A példány-operátorok az új példányok létrehozásának elkerülésével növelhetik a teljesítményt. A példányoperátornak a következő szabályokat kell követnie:

  • A módosítónak public tartalmaznia kell.
  • Nem tartalmazhatja a static módosítót.
  • A visszatérési típusnak meg kell lennie void.
  • Nem deklarálhat paramétereket, még akkor sem, ha ezek a paraméterek alapértelmezett értékkel rendelkeznek.

Nem túlterhelhető operátorok

Az alábbi táblázat azokat az operátorokat mutatja be, amelyek nem terhelhetők túl:

Működtetők Alternatívák
x && y, x || y Túlterhelje mind az true operátorokat false , mind az & operátorokat | . További információ: Felhasználó által definiált feltételes logikai operátorok.
a[i], a?[i] Indexelő definiálása.
(T)x Egyéni típuskonverziók definiálása, amelyeket egy öntött kifejezés hajt végre. További információ: Felhasználó által definiált konverziós operátorok.
^x, x = y, x.y, x?.yc ? t : f, x ?? y, ??= y
x..y, x->y, =>, f(x), as, await, checked, unchecked, default, delegate, is, nameof, new,
sizeof, stackalloc, switch, typeofwith
Nincs.

A C# 14 előtt az összetett operátorok nem terhelhetők túl. A megfelelő bináris operátor túlterhelése implicit módon túlterheli a megfelelő összetett hozzárendelési operátort.

Operátorok túlterhelésének feloldása

Fontos

Ez a szakasz a C# 14-es és újabb verzióira vonatkozik. C# 14 előtt a felhasználó által definiált összetett hozzárendelési operátorok, valamint a példány növekményes és csökkentő operátorok nem engedélyezettek.

Ha x változóként van besorolva egy összetett hozzárendelési kifejezésben, például x «op»= y, akkor a statikus operátorokkal szemben a példány-operátorok kapnak előnyt «op» esetében. Ha egy túlterhelt «op»= operátor nincs deklarálva a változó típusához x , vagy x nincs besorolva változóként, akkor a statikus operátorokat használja a rendszer.

Ha a postfix operátor ++x nem változóként van besorolva, vagy a kifejezést x++ használja, a rendszer figyelmen kívül hagyja a példánytoperator++. Ellenkező esetben a rendszer előnyben részesíti a példányt operator ++. Például

x++; // Instance operator++ preferred.
y = x++; // instance operator++ isn't considered.

Ennek a szabálynak az az oka, hogy y értékét xelőtt kell hozzárendelni, hogy az növelve legyen. A fordító nem tudja meghatározni, hogy egy felhasználó által meghatározott implementáció esetében referenciatípusban van-e.

Az előtag operátora ++ esetében, ha x változóként van besorolva ++x-ben, a példányoperátort előnyben részesítik a statikus unáris operátorral szemben.

C# nyelvspecifikáció

További információt a C# nyelvspecifikációjának alábbi szakaszaiban talál:

Lásd még