Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Ein benutzerdefinierter Typ kann einen vordefinierten C#-Operator überladen. Das heißt, ein Typ kann die benutzerdefinierte Implementierung eines Vorgangs bereitstellen, falls ein oder beide Operanden diesen Typ aufweisen. Im Abschnitt überladene Operatoren wird gezeigt, welche C#-Operatoren überladen werden können.
Verwenden Sie das operator
Schlüsselwort, um einen Operator zu deklarieren. Eine Operatordeklaration muss die folgenden Regeln erfüllen:
- Es enthält einen
public
-Modifikator. - Ein unärer Operator weist einen Eingabeparameter auf. Ein binärer Operator verfügt über zwei Eingabeparameter. Mindestens ein Parameter muss jeweils den Typ
T
oderT?
haben, wobeiT
der Typ ist, der die Operatordeklaration enthält. - Er enthält den
static
Modifizierer, mit Ausnahme der zusammengesetzten Zuordnungsoperatoren, z. B.+=
. - Die Operatoren inkrementieren (
++
) und dekrementieren (--
) können als statische oder Instanzmethoden implementiert werden.
Im folgenden Beispiel wird eine vereinfachte Struktur definiert, die eine rationale Zahl darstellt. Die Struktur überlastet einige der arithmetischen Operatoren:
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++, operand.denominator);
public static Fraction operator --(Fraction operand) =>
new Fraction(operand.numerator--, 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
}
}
Sie könnten das vorherige Beispiel erweitern, indem Sie eine implizite Konvertierung von int
nach Fraction
definieren. Anschließend würden überladene Operatoren Argumente dieser beiden Typen unterstützen. Das heißt, es wäre möglich, eine ganze Zahl zu einem Bruch hinzuzufügen und einen Bruch als Ergebnis zu erhalten.
Sie verwenden auch das operator
Schlüsselwort, um eine benutzerdefinierte Typkonvertierung zu definieren. Weitere Informationen finden Sie unter Benutzerdefinierte Konvertierungsoperatoren.
Überladbare Operatoren
In der folgenden Tabelle sind die Operatoren aufgeführt, die überladen werden können:
Betriebspersonal | Hinweise |
---|---|
+x , , -x !x , ~x , ++ , -- , , true false |
Die Operatoren true und false müssen zusammen überladen werden. |
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 |
Muss in Paaren wie folgt überladen werden: == und != , < und > , <= und >= . |
+= , -= , *= , /= , %= , &= , \|= , ^= , <<= , >>= , >>>= |
Die zusammengesetzten Zuweisungsoperatoren können in C# 14 und höher überladen werden. |
Ein überladener Operator für eine zusammengesetzte Zuweisung muss diese Regeln befolgen:
- Er muss den
public
Modifizierer enthalten. - Er kann den
static
Modifizierer nicht enthalten. - Der Rückgabetyp muss sein
void
. - Die Deklaration muss einen Parameter enthalten, der die rechte Seite der Verbundzuordnung darstellt.
Seit C# 14 können die Inkrement- (++
) und Dekrementoperatoren (--
) als Instanzmember überladen werden. Instanzoperatoren können die Leistung verbessern, indem sie die Erstellung einer neuen Instanz vermeiden. Ein Instanzoperator muss den folgenden Regeln entsprechen:
- Er muss den
public
Modifizierer enthalten. - Er kann den
static
Modifizierer nicht enthalten. - Der Rückgabetyp muss sein
void
. - Sie kann keine Parameter deklarieren, auch wenn diese Parameter über einen Standardwert verfügen.
Nicht überladbare Operatoren
Die folgende Tabelle zeigt die Operatoren, die nicht überladen werden können:
Betriebspersonal | Alternativen |
---|---|
x && y , x || y |
Überladen Sie sowohl die true - und false -Operatoren als auch die & - oder | -Operatoren. Weitere Informationen finden Sie unter benutzerdefinierte bedingte logische Operatoren. |
a[i] , a?[i] |
Definieren Sie einen Indexer. |
(T)x |
Definieren Sie angepasste Konversionen, die von einem Cast-Ausdruck ausgeführt werden. Weitere Informationen finden Sie unter Benutzerdefinierte Konvertierungsoperatoren. |
^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 |
Keiner. |
Vor C# 14 können die zusammengesetzten Operatoren nicht überladen werden. Durch das Überladen des entsprechenden binären Operators wird implizit der entsprechende Verbundzuordnungsoperator überladen.
Überladungsauflösung von Operatoren
Von Bedeutung
Dieser Abschnitt gilt für C# 14 und höher. Vor C# 14 sind benutzerdefinierte Verbundzuordnungsoperatoren und Instanzinkrementierer und Dekrementoperatoren nicht zulässig.
Wenn x
in einem zusammengesetzten Zuordnungsausdruck wie x «op»= y
als Variable klassifiziert wird, werden Instanzoperatoren gegenüber statischen Operatoren bevorzugt für «op»
. Wenn ein überladener «op»=
Operator nicht für den Typ von x
erklärt ist oder x
nicht als Variable klassifiziert ist, werden die statischen Operatoren verwendet.
Wenn der Postfix-Operator ++
x
nicht als Variable klassifiziert wird oder der Ausdruck x++
verwendet wird, wird die Instanz operator++
ignoriert. Andernfalls erhält die Instanz operator ++
die Vorzug. Beispiel:
x++; // Instance operator++ preferred.
y = x++; // instance operator++ isn't considered.
Der Grund für diese Regel ist, dass y
dem Wert x
vor dem Inkrementieren zugewiesen werden soll. Der Compiler kann dies für eine benutzerdefinierte Implementierung in einem Referenztyp nicht bestimmen.
Wenn der Präfixoperator ++
für x
als Variable in ++x
klassifiziert wird, wird der Instanzoperator gegenüber einem statischen unären Operator bevorzugt.
C#-Sprachspezifikation
Weitere Informationen finden Sie in den folgenden Abschnitten der C#-Sprachspezifikation: