|
Operatoren
Was sind Operatoren?
Nachdem Felder und Variablen nun bekannt sind, können Anwendungen Daten speichern und auch
wieder abrufen. Allerdings fehlt noch eine Möglichkeit, Daten zu verändern, um beispielsweise
Berechnungen ausführen oder Daten miteinander verknüpfen zu können. Die Änderung von Daten
wird in C# durch sogenannte Operatoren unterstützt, deren einfachster der bereits bekannte
Zuweisungsoperator = ist.
Arithmetische Operatoren
Den ersten Typ von Operatoren stellen in C# die arithmetischen Operatoren dar, die zum
Rechnen mit Daten dienen. Arithmetische Operatoren können mit allen Wertetypen verwendet
werden, die Zahlen darstellen, wobei darauf geachtet werden muss, dass die beiden
miteinander zu verrechnenden Werte den gleichen Typ aufweisen.
| + |
Addition |
| C# |
1
2
3
4
5
|
int x = 2;
int y = 3;
// The sum is 5.
int sum = x + y;
|
|
| - |
Subtraktion |
| C# |
1
2
3
4
5
|
int x = 2;
int y = 3;
// The difference is -1.
int difference = x - y;
|
|
| * |
Multiplikation |
| C# |
1
2
3
4
5
|
int x = 2;
int y = 3;
// The product is 6.
int product = x * y;
|
|
| / |
Division |
| C# |
1
2
3
4
5
|
int x = 2;
int y = 3;
// The quotient is 0.
int quotient = x / y;
|
|
| % |
Modulo |
| C# |
1
2
3
4
5
|
int x = 2;
int y = 3;
// The remainder is 2.
int remainder = x % y;
|
|
C# rechnet dabei nach den üblichen mathematischen Regeln, das heißt, es gilt Punkt- vor
Strichrechnung. Allerdings kann diese Regelung - wie in der Mathematik auch - durch das
Setzen von Klammern geändert werden.
| C# |
1
2
3
4
5
6
7
|
int x = 2;
int y = 3;
int z = 5;
// The result without brackets is 17, with brackets it is 25.
int resultA = x + y * z;
int resultB = (x + y) * z;
|
Während sich die Operatoren +, - und * so verhalten, wie man es erwarten würde, gibt es
bei den beiden Divisionsoperatoren / und % einige Sonderfälle zu beachten. Zunächst ist
das Ergebnis einer Verknüpfung von zwei Operanden mit einem arithmetischen Operator wieder
vom gleichen Typ wie die beiden Operanden.
Wenn allerdings zwei Operanden von einem ganzzahligen Typ wie beispielsweise int
oder long dividiert werden sollen, ist das Ergebnis unter Umständen
nicht ganzzahlig. Deshalb werden in diesem Fall die Nachkommastellen abgeschnitten und nur
der ganzzahlige Anteil als Ergebnis zurückgegeben.
| C# |
1
2
3
4
5
6
7
8
9
10
11
|
int x = 4;
int y = 2;
// The quotient is 2, since the result is an integer (2).
int quotient = x / y;
x = 3;
// The quotient is 1, since the result is not an integer (1,5) and
// hence the decimal part is cut off.
quotient = x / y;
|
Außerdem muss darauf geachtet werden, dass bei der Division nicht durch die Zahl Null
geteilt wird, da dies mathematisch nicht definiert ist und zur Laufzeit der Anwendung
ein entsprechender Fehler ausgelöst wird.
Die einzige Ausnahme von der Regel, dass arithmetische Operatoren mit jedem Wertetyp
verwendet werden können, der Zahlen darstellt, ist der Modulo-Operator %, der nur für
ganzzahlige Operanden definiert ist. Der Modulo-Operator gibt den Rest zurück, der
entsteht, wenn der eine Operand durch den anderen geteilt wird.
| C# |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
int x = 1;
int y = 3;
// The remainder is 1, since 3 is not contained in 1, so there
// is 1 left.
int remainder = x % y;
x = 2;
// The remainder is 2, since 3 is not contained in 2, so there
// is 2 left.
remainder = x % y;
x = 3;
// The remainder is 0, since 3 is contained one time in 3, so there
// is 0 left.
remainder = x % y;
|
Die Modulo-Division entspricht also in gewisser Weise der Art, wie Uhrzeiten berechnet
werden. Eine Uhr könnte die Stunden intern nämlich fortlaufend zählen, diese für die
Ausgabe allerdings modulo zwölf rechnen.
Häufig kommt es vor, dass eine Variable mit sich selbst verrechnet wird, indem ihr Wert
beispielsweise verdoppelt werden soll. Um den Wert einer Variablen i zu verdoppeln, muss
dieser mit zwei multipliziert und das Ergebnis anschließend wieder der Variablen i
zugewiesen werden.
Da Berechnungen dieser Art häufig auftreten, gibt es eine kürzere Schreibweise für diesen
Fall, bei dem eine Nennung der Variablen entfallen kann, und der Zuweisungsoperator seinen
Platz mit dem arithmetischen Operator tauscht, wobei dieses Verfahren mit jedem
arithmetischen Operator funktioniert.
| C# |
1
2
|
// Adequate to i = i * 2.
i *= 2;
|
Für die besonders häufig auftretenden Fälle, dass eine Variable um eins erhöht oder
vermindert werden muss, gibt es sogar eine noch kürzere Schreibweise, indem die Variable
mit dem Operator ++ oder -- verknüpft wird. Da dieser Operator keinen zweiten Operanden
benötigt, wird er als unärer Operator bezeichnet, wohingegen die anderen arithmetischen
Operatoren binäre Operatoren sind.
| C# |
1
2
|
// Adequate to i = i + 1.
i++;
|
Für die beiden unären Operatoren ++ und -- gibt es allerdings zwei Varianten - der Operator
kann nämlich entweder hinter der Variablen, in der sogenannten Postfix-Notation, oder vor
der Variablen, in der sogenannten Präfix-Notation angegeben werden. Der Unterschied liegt
darin, ob zuerst der Wert verändert oder zuerst das Ergebnis zurückgegeben wird.
| C# |
1
2
3
4
5
6
7
8
|
int i = 3;
// Prints 3 to the console and increments i afterwards to 4.
Console.WriteLine(i++);
// Prints 5 to the console, since i is incremented before it
// gets printed.
Console.WriteLine(++i);
|
Schließlich gibt es noch zwei spezielle Fälle, die berücksichtigt werden müssen: Der
mathematische Über- beziehungsweise Unterlauf. Ein Überlauf tritt immer dann auf, wenn
das Resultat einer Berechnung zu groß für den entsprechenden Typ ist, ein Unterlauf analog
dazu, wenn das Resultat zu klein ist.
Sofern diese beiden Fälle nicht gesondert berücksichtigt werden, treten Rechenfehler auf,
sobald der größt- oder kleinstmögliche Wert über- oder unterschritten wurden. Die Anwendung
wird ansonsten aber weiterhin ausgeführt. Falls eine explizite Überprüfung erforderlich ist,
kann diese mit dem Schlüsselwort checked für einen abgeschlossenen
Codeabschnitt aktiviert werden.
| C# |
1
2
3
4
5
6
7
8
|
int x = 2;
int y = 3;
// Activate checked calculations.
checked
{
Console.WriteLine(x + y);
}
|
Im Fall eines Über- oder Unterlaufs tritt wie bei einer Division durch Null ein Fehler auf.
So nützlich der Einsatz von checked ist, so sollte dennoch berücksichtigt
werden, dass diese Prüfung Rechenzeit erfordert und die Anwendung daher an den zu prüfenden
Stellen verlangsamt, und dass diese Prüfung einen Spezialfall prüft, der in der Praxis nicht all
zu häufig auftritt. Ob checked verwendet wird oder nicht, hängt also
vom konkreten Bedarf ab.
Sofern eine Anwendung generell als checked ausgeführt werden soll,
kann dem Compiler dies durch den Parameter /checked mitgeteilt werden. Auf diese Art ist es
nicht notwendig, alle Stellen innerhalb des Codes mit dem Schlüsselwort checked
zu kennzeichnen. Allerdings ist es möglich, einzelne Stellen innerhalb des Codes mit dem Schlüsselwort
unchecked zu kennzeichnen, um sie von der generellen Prüfung auszuschließen,
wobei dieses Schlüsselwort genauso verwendet wird wie checked.
| C# |
1
2
3
4
5
6
7
8
|
int x = 2;
int y = 3;
// Activate unchecked calculations.
unchecked
{
Console.WriteLine(x + y);
}
|
Relationale Operatoren
Im Gegensatz zu arithmetischen Operatoren dienen die relationalen Operatoren dazu, etwas
über das Verhältnis zweier Operanden auszusagen. Mit ihnen kann geprüft werden, ob die
beiden Operanden gleich, ungleich, größer, kleiner, größer gleich oder kleiner gleich sind.
Als Resultat wird immer ein Wahrheitswert zurückgegeben, der angibt, ob die angegebene
Relation wahr oder falsch ist.
| == |
gleich |
| C# |
1
2
3
4
5
|
int x = 2;
int y = 3;
// x and y are not equal, hence false.
bool result = x == y;
|
|
| != |
ungleich |
| C# |
1
2
3
4
5
|
int x = 2;
int y = 3;
// x and y are not equal, hence true.
bool result = x != y;
|
|
| > |
größer |
| C# |
1
2
3
4
5
|
int x = 2;
int y = 3;
// x is not greater than y, hence false.<br />
bool result = x > y;
|
|
| < |
kleiner |
| C# |
1
2
3
4
5
|
int x = 2;
int y = 3;
// x is smaller than y, hence true.
bool result = x < y;
|
|
| >= |
größer oder gleich |
| C# |
1
2
3
4
5
|
int x = 2;
int y = 3;
// x is not greater than or equal to y, hence false.
bool result = x >= y;
|
|
| <= |
kleiner oder gleich |
| C# |
1
2
3
4
5
|
int x = 2;
int y = 3;
// x is smaller than or equal to y, hence true.
bool result = x <= y;
|
|
Es gilt als guter Stil, die beiden Operanden mitsamt dem relationalen Operator zu klammern,
um die Lesbarkeit zu verbessern. An Stelle von
| C# |
1
|
bool result = foo == bar;
|
würde man also
| C# |
1
|
bool result = (foo == bar);
|
schreiben.
Relationale Operatoren können prinzipiell zwar auf alle Wertetypen angewandt werden,
allerdings ist dies nur begrenzt sinnvoll. Da Dezimalzahlen von Prozessoren intern nicht
exakt dargestellt werden können, kann man sich nicht darauf verlassen, dass zwei
anscheinend gleich große Zahlen des Typs float, double
oder decimal bei einem Vergleich mit dem Operator == das Literal
true als Ergebnis liefern. Dezimalzahlen sollten immer
nur mit Hilfe von >, <, >= und <= verglichen werden.
Verweistypen können zumindest mit Hilfe der Operatoren == und != verglichen werden, wobei
dies eine andere Semantik als bei Wertetypen hat. Während bei Wertetypen der tatsächliche
Wert verglichen wird, wird bei Verweistypen lediglich die Referenz verglichen. Sofern zwei
Variablen also eine Referenz auf das identische Objekt enthalten, wird bei einem Vergleich
mit == das Literal true zurückgeliefert. Enthalten sie aber Referenzen
auf zwei verschiedene Objekte, die zwar in ihren Werten, aber nicht in ihrer Objektidentität
übereinstimmen, so liefert der Vergleich das Literal false.
| C# |
1
2
3
4
5
6
7
8
9
10
11
12
|
ComplexNumber foo = new ComplexNumber(23, 42);
ComplexNumber bar = foo;
// Returns true, since foo and bar reference the identical
// object.
Console.WriteLine(foo == bar);
y = new ComplexNumber(23, 42);
// Returns false, since foo and bar reference different
// objects, even if they have the same value.
Console.WriteLine(foo == bar);
|
Logische Operatoren
Während relationale Operatoren einen Vergleich zwischen den beiden Operanden durchführen,
verknüpfen logische Operatoren diese. Logische Operatoren können im Gegensatz zu den
anderen Operatoren nur auf Operanden des Typs bool angewandt werden
und liefern auch als Ergebnis einen Wert des Typs bool.
| && |
und |
Ergibt true, wenn beide Operanden true sind. |
| C# |
1
2
3
4
5
|
bool x = true;
bool y = false;
// x and y are not both true, hence false.
bool result = x && y;
|
|
| || |
oder |
Ergibt true, wenn mindestens einer der beiden Operanden true ist. |
| C# |
1
2
3
4
5
|
bool x = true;
bool y = false;
// At least one of x and y is true, hence true.
bool result = x || y;
|
|
| ^ |
exklusives oder |
Ergibt true, wenn genau einer der beiden Operanden true ist. |
| C# |
1
2
3
4
5
|
bool x = true;
bool y = false;
// x is true, y is not, hence true.
bool result = x ^ y;
|
|
| ! |
nicht |
Ergibt true, wenn der Operand false ist, und umgekehrt. |
| C# |
1
2
3
4
|
bool x = true;
// x is true, hence false.
bool result = !x;
|
|
C# verwendet bei der Auswertung logischer Operatoren die sogenannte Kurzschlussevaluierung.
Dies bedeutet, dass für die Auswertung eines Operators unter Umständen nicht alle Operanden
überprüft werden - ist beispielsweise bei einer und-Verknüpfung bereits der erste Operand
false, so kann das Ergebnis nicht true sein,
unabhängig davon, welchen Wert der zweite Operand aufweist. Daher wird dieser nicht mehr überprüft
und direkt false zurückgegeben.
Bitweise Operatoren
Bitweise Operatoren ähneln logischen Operatoren sehr stark, allerdings werden sie nicht für
Wahrheitswerte, sondern für Ganzzahlen verwendet. Die Überprüfung findet dementsprechend
auch nicht auf den Wahrheitswerten der Operanden statt, sondern auf Bitebene der Operanden.
| & |
und |
Ergibt 1, wenn beide Bits 1 sind. |
| C# |
1
2
3
4
5
|
int x = 23;
int y = 42;
// x is binary 010111 and y is binary 101010, hence 000010, which is 2.
int result = x & y;
|
|
| | |
oder |
Ergibt 1, wenn mindestens eines der beiden Bits 1 ist. |
| C# |
1
2
3
4
5
|
int x = 23;
int y = 42;
// x is binary 010111 and y is binary 101010, hence 111111, which is 63.
int result = x | y;
|
|
| ^ |
exklusives oder |
Ergibt 1, wenn genau eines der beiden Bits 1 ist. |
| C# |
1
2
3
4
5
|
int x = 23;
int y = 42;
// x is binary 010111 and y is binary 101010, hence 111101, which is 61.
int result = x ^ y;
|
|
| ~ |
nicht |
Ergibt 1, wenn das Bit 0 ist, und umgekehrt. |
| C# |
1
2
3
4
|
int x = 23;
// x is binary 010111, hence 101000, which is -24 due to internal reasons.
int result = ~x;
|
|
| << |
verschieben nach links |
Schiebt alle Bits um die angegebene Anzahl nach links. |
| C# |
1
2
3
4
|
int x = 23;
// x is binary 010111, hence 101110, which is 46.
int result = x << 1;
|
|
| >> |
verschieben nach rechts |
Schiebt alle Bits um die angegebene Anzahl nach rechts. |
| C# |
1
2
3
4
|
int x = 23;
// x is binary 010111, hence 001011, which is 11.
int result = x >> 1;
|
|
Bitweise Operatoren werden häufig verwendet, um zu überprüfen, ob einzelne Bits gesetzt
sind, oder um diese zu setzen beziehungsweise zu löschen. Ebenso wie arithmetische Operatoren
können bitweise Operatoren mit dem Zuweisungsoperator zu einer verkürzten Schreibweise
zusammengezogen werden.
Zeichenkettenoperatoren
Zeichenketten erfahren in C# eine Sonderbehandlung. Obwohl sie technisch gesehen
Verweistypen sind, verhalten sie sich größtenteils wie Wertetypen, was ihre Handhabung
teilweise deutlich erleichtert.
So liefert der Vergleich von zwei Strings mit Hilfe von == und != ein Ergebnis, als wären
Strings Wertetypen - enthalten sie den gleichen Text, sind sie gleich. Außerdem können
Strings mit Hilfe von <, >, <= und >= alphabetisch miteinander verglichen
werden. Ein String gilt dann als kleiner als ein anderer, wenn er im Alphabet vorher
einzuordnen ist.
| C# |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
string foo = "Hello";
string bar = "World";
// foo and bar do not contain the same text, hence false.
bool result = (foo == bar);
// foo and bar do not contain the same text, hence true.
result = (foo != bar);
// foo is alphabetically prior to bar, hence true.
result = (foo < bar);
// foo is alphabetically not superior to bar, hence false.
result = (foo > bar);
// foo is alphabetically prior or equal to bar, hence true.
result = (foo <= bar);
// foo is alphabetically neither superior nor equal to bar,
// hence false.
result = (foo >= bar);
|
Zudem können Strings mit dem Operator + aneinander gehängt werden, so dass sie einen neuen
zusammenhängenden String ergeben. Dieser Vorgang wird auch als Konkatenation bezeichnet.
| C# |
1
2
3
4
5
|
string foo = "Hello ";
string bar = "world!";
// The result is "Hello world!".
string result = foo + bar;
|
Ob ein String leer ist, kann geprüft werden, indem er mit dem leeren String "" verglichen
wird. Alternativ kann auch die Eigenschaft Empty der Klasse String verwendet werden. Eine
weitere Möglichkeit ist, die Eigenschaft Length des Strings zu prüfen, ob diese dem Wert
Null entspricht.
Da der Vergleich auf die Länge auf Grund der internen Organisation von Strings am
schnellsten ausgeführt werden kann, gilt es als guter Stil, diese Variante zu verwenden.
| C# |
1
2
3
4
5
6
|
string foo = "Hello";
// foo is not empty, hence false.
bool result = (foo == "");
result = (foo == String.Empty);
result = (foo.Length == 0);
|
Ob ein String leer oder eventuell sogar null ist, kann mit der statischen Methode
IsNullOrEmpty der Klasse string ermittelt werden.
| C# |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
string foo = null;
// foo is null, hence true.
bool result = String.IsNullOrEmpty(foo);
foo = "";
// foo is empty, hence true.
result = String.IsNullOrEmpty(foo);
foo = "Hello";
// foo is neither null nor empty, hence false.
result = String.IsNullOrEmpty(foo);
|
Operatorreihenfolge
Falls mehrere Operatoren gleichzeitig in einer Anweisung verwendet werden, werden diese
zunächst von links nach rechts verarbeitet. Allerdings verfügen einige Operatoren über eine
höhere Priorität als andere, so dass die Verarbeitung diesen Regeln folgt - ähnlich den
Regeln bei den arithmetischen Operatoren.
Die Operatoren haben folgende Priorität, wobei die höchstpriorisierten Operatoren an
oberster Stelle stehen:
| (), [] |
| ++ (postfix), -- (postfix), ++ (präfix), -- (präfix), ~, ! |
| *, /, % |
| +, - |
| >>, >>>, << |
| >, >=;, <, <= |
| ==, != |
| & |
| ^ |
| | |
| && |
| || |
| ?: |
| =, <operator>= |
Mit Hilfe von Operatoren können nun die meisten Methoden der Klasse ComplexNumber
implementiert werden.
| C# |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
using System;
namespace GoloRoden.GuideToCSharp
{
/// <summary>
/// Executes when storing begins.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
public delegate void StoringEventHandler(
object sender, EventArgs eventArguments);
/// <summary>
/// Executes when storing has finished.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
public delegate void StoredEventHandler(
object sender, EventArgs eventArguments);
/// <summary>
/// Executes when restoring begins.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
public delegate void RestoringEventHandler(
object sender, EventArgs eventArguments);
/// <summary>
/// Executes when restoring has finished.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
public delegate void RestoredEventHandler(
object sender, EventArgs eventArguments);
/// <summary>
/// Represents a complex number.
/// </summary>
public sealed class ComplexNumber : IPersistable
{
#region Properties
#endregion
#region Events
#endregion
#region Methods
// ...
/// <summary>
/// Calculates the conjugation.
/// </summary>
public void Conjugate()
{
// Calculate the conjugation.
this._imaginaryPart *= -1;
}
/// <summary>
/// Adds the specified summand to the current complex
/// number.
/// </summary>
/// <param name="summand">The complex number that is used
/// as summand.</param>
public void Add(ComplexNumber summand)
{
// Add the summand to the current complex
this._realPart += summand.RealPart;
this._imaginaryPart += summand.ImaginaryPart;
}
/// <summary>
/// Adds the specified summand to the current complex
/// number.
/// </summary>
/// <param name="summand">The real number that is used as
/// summand.</param>
public void Add(float summand)
{
// Add the summand to the current complex
this._realPart += summand;
}
/// <summary>
/// Multiplies the current complex number with the
/// specified factor.
/// </summary>
/// <param name="factor">The complex number that is
/// used as factor.</param>
public void Multiply(ComplexNumber factor)
{
// Multiply the factor with the current complex
// number.
float? newRealPart =
(this.RealPart * factor.RealPart) -
(this.ImaginaryPart * factor.ImaginaryPart);
float? newImaginaryPart =
(this.RealPart * factor.ImaginaryPart) +
(this.ImaginaryPart * factor.RealPart);
// Assign the new values to the current complex
// number.
this.RealPart = newRealPart;
this.ImaginaryPart = newImaginaryPart;
}
/// <summary>
/// Multiplies the current complex number with the
/// specified factor.
/// </summary>
/// <param name="factor">The real number that is
/// used as factor.</param>
public void Multiply(float factor)
{
// Multiply the factor with the current complex
// number.
this.Multiply(new ComplexNumber(factor));
}
#endregion
#region Constructors
#endregion
}
}
|
Überladen von Operatoren
Zwar ist es mit Hilfe dieser Operatoren nun möglich, Berechnungen mit komplexen Zahlen
durchzuführen, allerdings muss für jede einzelne Operation eine eigene Methode aufgerufen
werden. So muss beispielsweise für die Addition zweier komplexer Zahlen die entsprechende
Methode Add verwendet werden, welche die als Parameter übergebene komplexe Zahl zu der
addiert, an der die Methode aufgerufen wird.
| C# |
1
|
firstComplexNumber.Add(secondComplexNumber);
|
Obwohl dieses Vorgehen funktioniert, entspricht die sich dadurch ergebende Syntax nicht
der aus der Mathematik gewohnten Schreibweise, in der zwischen den beiden zu addierenden
Zahlen ein + angegeben wird.
Der Grund, warum eine Addition komplexer Zahlen mit Hilfe des Symbols + in C# nicht
funktioniert, ist offensichtlich: Die Klasse ComplexNumber ist für .NET eine beliebige,
vom Benutzer definierte Klasse, deren mathematische Eigenheiten nur dem Entwickler bekannt
sind. In C# ist also schlichtweg nicht definiert, welche Bedeutung dem Symbol + für
komplexe Zahlen innewohnt.
Allerdings lassen sich Operatoren - und nichts anderes stellt das Symbol + in C# dar -
für benutzerdefinierte Klassen überladen, so dass eigene Datentypen in mathematischen
Ausdrücken unter Verwendung der klassischen Syntax miteinander verrechnet werden
können.
Um einen Operator zu überladen, genügt es, eine entsprechende Methode innerhalb der
Klasse zu definieren, für die der Operator gelten soll. Als Methodenname wird dabei
der Operator an sich angegeben, zusätzlich muss ihm allerdings noch das Schlüsselwort
operator vorangestellt werden. Außerdem muss beachtet
werden, dass operatorüberladende Methoden immer klassengebunden, also mit dem
Schlüsselwort static gekennzeichnet werden müssen.
Als Parameter werden dabei die einzelnen Operanden angegeben, die miteinander verrechnet
werden sollen. Die Anzahl der Parameter bestimmt sich dabei aus der Anzahl der Operanden,
die für den jeweiligen Operator benötigt werden. Die Operatoren + und * erwarten
beispielsweise zwei Operanden, der Operator ! hingegen nur einen.
Der Typ des Rückgabewerts entspricht in jedem Fall der Klasse, in welcher der überladene
Operator definiert wird.
| C# |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
using System;
namespace GoloRoden.GuideToCSharp
{
/// <summary>
/// Executes when storing begins.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
public delegate void StoringEventHandler(
object sender, EventArgs eventArguments);
/// <summary>
/// Executes when storing has finished.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
public delegate void StoredEventHandler(
object sender, EventArgs eventArguments);
/// <summary>
/// Executes when restoring begins.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
public delegate void RestoringEventHandler(
object sender, EventArgs eventArguments);
/// <summary>
/// Executes when restoring has finished.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
public delegate void RestoredEventHandler(
object sender, EventArgs eventArguments);
/// <summary>
/// Represents a complex number.
/// </summary>
public sealed class ComplexNumber : IPersistable
{
#region Properties
#endregion
#region Events
#endregion
#region Operators
/// <summary>
/// Adds the specified complex numbers.
/// </summary>
/// <param name="firstSummand">The complex number
/// that is used as first summand.</param>
/// <param name="secondSummand">The complex number
/// that is used as second summand.</param>
/// <returns>The sum of the specified complex
/// numbers.</returns>
public static ComplexNumber operator +(
ComplexNumber firstSummand,
ComplexNumber secondSummand)
{
// Add the two complex numbers.
ComplexNumber result =
new ComplexNumber(
firstSummand.RealPart,
firstSummand.ImaginaryPart);
result.Add(secondSummand);
// Return the result to the caller.
return result;
}
/// <summary>
/// Multiplies the specified complex numbers.
/// </summary>
/// <param name="firstFactor">The complex number
/// that is used as first factor.</param>
/// <param name="secondFactor">The complex number
/// that is used as second factor.</param>
/// <returns>The product of the specified complex
/// numbers.</returns>
public static ComplexNumber operator *(
ComplexNumber firstFactor,
ComplexNumber secondFactor)
{
// Multiply the two complex numbers.
ComplexNumber result =
new ComplexNumber(
firstFactor.RealPart,
firstFactor.ImaginaryPart);
result.Multiply(secondFactor);
// Return the result to the caller.
return result;
}
#endregion
#region Methods
#endregion
#region Constructors
#endregion
}
}
|
Überladene Operatoren ermöglichen in C# nicht nur, gleichartige Operanden miteinander
zu verrechnen, sondern es können auch Operatoren verschiedener Typen angegeben werden.
Allerdings muss mindestens einer der Operanden immer der Klasse entsprechen, in welcher
der Operator überladen wird. Es ist also beispielsweise nicht möglich, in der Klasse
ComplexNumber die Addition für zwei Operanden des Typs int zu überladen.
| C# |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
using System;
namespace GoloRoden.GuideToCSharp
{
/// <summary>
/// Executes when storing begins.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
public delegate void StoringEventHandler(
object sender, EventArgs eventArguments);
/// <summary>
/// Executes when storing has finished.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
public delegate void StoredEventHandler(
object sender, EventArgs eventArguments);
/// <summary>
/// Executes when restoring begins.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
public delegate void RestoringEventHandler(
object sender, EventArgs eventArguments);
/// <summary>
/// Executes when restoring has finished.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
public delegate void RestoredEventHandler(
object sender, EventArgs eventArguments);
/// <summary>
/// Represents a complex number.
/// </summary>
public sealed class ComplexNumber : IPersistable
{
#region Properties
#endregion
#region Events
#endregion
#region Operators
/// <summary>
/// Adds the specified complex numbers.
/// </summary>
/// <param name="firstSummand">The complex number
/// that is used as first summand.</param>
/// <param name="secondSummand">The complex number
/// that is used as second summand.</param>
/// <returns>The sum of the specified complex
/// numbers.</returns>
public static ComplexNumber operator +(
ComplexNumber firstSummand,
ComplexNumber secondSummand)
{
// Add the two complex numbers.
ComplexNumber result =
new ComplexNumber(
firstSummand.RealPart,
firstSummand.ImaginaryPart);
result.Add(secondSummand);
// Return the result to the caller.
return result;
}
/// <summary>
/// Adds the specified summand to the specified
/// complex number.
/// </summary>
/// <param name="complexNumber">The complex number
/// that is used as first summand.</param>
/// <param name="summand">The summand that is used
/// as second summand.</param>
/// <returns>The sum of the specified complex number
/// and the specified summand.</returns>
public static ComplexNumber operator +(
ComplexNumber complexNumber, float summand)
{
// Add the two complex numbers.
ComplexNumber result =
new ComplexNumber(
complexNumber.RealPart,
complexNumber.ImaginaryPart);
result.Add(summand);
// Return the result to the caller.
return result;
}
/// <summary>
/// Multiplies the specified complex numbers.
/// </summary>
/// <param name="firstFactor">The complex number
/// that is used as first factor.</param>
/// <param name="secondFactor">The complex number
/// that is used as second factor.</param>
/// <returns>The product of the specified complex
/// numbers.</returns>
public static ComplexNumber operator *(
ComplexNumber firstFactor,
ComplexNumber secondFactor)
{
// Multiply the two complex numbers.
ComplexNumber result =
new ComplexNumber(
firstFactor.RealPart,
firstFactor.ImaginaryPart);
result.Multiply(secondFactor);
// Return the result to the caller.
return result;
}
/// <summary>
/// Multiplies the specified complex number with
/// the specified factor.
/// </summary>
/// <param name="complexNumber">The complex number
/// that is used as first factor.</param>
/// <param name="factor">The factor that is used
/// as second factor.</param>
/// <returns>The product of the specified complex
/// number and the specified factor.</returns>
public static ComplexNumber operator *(
ComplexNumber complexNumber, float factor)
{
// Multiply the two complex numbers.
ComplexNumber result =
new ComplexNumber(
complexNumber.RealPart,
complexNumber.ImaginaryPart);
result.Multiply(factor);
// Return the result to the caller.
return result;
}
#endregion
#region Methods
#endregion
#region Constructors
#endregion
}
}
|
Bei der Überladung von Operatoren gibt es drei Einschränkungen, die beachtet werden
müssen: Zum einen können in C# einige Operatoren nicht überladen werden, dazu zählen
insbesondere der Zuweisungsoperator, sämtliche Klammern und auch alle Operatoren, die
nicht durch ein Symbol wie + oder *, sondern durch ein Schlüsselwort repräsentiert
werden.
Zum zweiten können einige Operatoren nur paarweise überladen werden, was insbesondere
für die relationalen Operatoren gilt. Das heißt, wird beispielsweise der Operator >
überladen, so muss auch der entsprechende Operator < überladen werden.
Zu guter letzt ist es nicht möglich, die verkürzte Schreibweise, die einen Operator
mit dem Zuweisungsoperator verbindet, getrennt von dem eigentlichen Operator zu überladen.
Wird also zum Beispiel der Operator + überladen, so wird dadurch implizit auch der
Operator += überladen.
|