Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort zur 6. Auflage
1 Allgemeine Einführung in .NET
2 Grundlagen der Sprache C#
3 Das Klassendesign
4 Vererbung, Polymorphie und Interfaces
5 Delegates und Ereignisse
6 Strukturen und Enumerationen
7 Fehlerbehandlung und Debugging
8 Auflistungsklassen (Collections)
9 Generics – Generische Datentypen
10 Weitere C#-Sprachfeatures
11 LINQ
12 Arbeiten mit Dateien und Streams
13 Binäre Serialisierung
14 XML
15 Multithreading und die Task Parallel Library (TPL)
16 Einige wichtige .NET-Klassen
17 Projektmanagement und Visual Studio 2012
18 Einführung in die WPF und XAML
19 WPF-Layout-Container
20 Fenster in der WPF
21 WPF-Steuerelemente
22 Elementbindungen
23 Konzepte von WPF
24 Datenbindung
25 Weitere Möglichkeiten der Datenbindung
26 Dependency Properties
27 Ereignisse in der WPF
28 WPF-Commands
29 Benutzerdefinierte Controls
30 2D-Grafik
31 ADO.NET – Verbindungsorientierte Objekte
32 ADO.NET – Das Command-Objekt
33 ADO.NET – Der SqlDataAdapter
34 ADO.NET – Daten im lokalen Speicher
35 ADO.NET – Aktualisieren der Datenbank
36 Stark typisierte DataSets
37 Einführung in das ADO.NET Entity Framework
38 Datenabfragen des Entity Data Models (EDM)
39 Entitätsaktualisierung und Zustandsverwaltung
40 Konflikte behandeln
41 Plain Old CLR Objects (POCOs)
Stichwort

Download:
- Beispiele, ca. 62,4 MB

Jetzt Buch bestellen
Ihre Meinung?

Spacer
Visual C# 2012 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2012

Visual C# 2012
Rheinwerk Computing
1402 S., 6., aktualisierte und erweiterte Auflage 2013, geb., mit DVD
49,90 Euro, ISBN 978-3-8362-1997-6
Pfeil 10 Weitere C#-Sprachfeatures
Pfeil 10.1 Implizit typisierte Variablen
Pfeil 10.2 Anonyme Typen
Pfeil 10.3 Lambda-Ausdrücke
Pfeil 10.3.1 Projektion und Prädikat
Pfeil 10.4 Erweiterungsmethoden
Pfeil 10.5 Partielle Methoden
Pfeil 10.5.1 Wo partielle Methoden eingesetzt werden
Pfeil 10.6 Operatorüberladung
Pfeil 10.6.1 Einführung
Pfeil 10.6.2 Die Syntax der Operatorüberladung
Pfeil 10.6.3 Die Operatorüberladungen im Projekt »GeometricObjectsSolution«
Pfeil 10.6.4 Die Operatoren »true« und »false« überladen
Pfeil 10.6.5 Benutzerdefinierte Konvertierungen
Pfeil 10.7 Indexer
Pfeil 10.7.1 Überladen von Indexern
Pfeil 10.7.2 Parameterbehaftete Eigenschaften
Pfeil 10.8 Attribute
Pfeil 10.8.1 Das »Flags«-Attribut
Pfeil 10.8.2 Benutzerdefinierte Attribute
Pfeil 10.8.3 Attribute auswerten
Pfeil 10.8.4 Festlegen der Assembly-Eigenschaften in »Assembly-Info.cs«
Pfeil 10.9 Dynamisches Binden
Pfeil 10.9.1 Eine kurze Analyse
Pfeil 10.9.2 Dynamische Objekte
Pfeil 10.10 Unsicherer (unsafe) Programmcode – Zeigertechnik in C#
Pfeil 10.10.1 Einführung
Pfeil 10.10.2 Das Schlüsselwort »unsafe«
Pfeil 10.10.3 Die Deklaration von Zeigern
Pfeil 10.10.4 Die »fixed«-Anweisung
Pfeil 10.10.5 Zeigerarithmetik
Pfeil 10.10.6 Der Operator »->«

Rheinwerk Computing - Zum Seitenanfang

10.6 OperatorüberladungZur nächsten Überschrift


Rheinwerk Computing - Zum Seitenanfang

10.6.1 EinführungZur nächsten ÜberschriftZur vorigen Überschrift

C# verfügt über eine Reihe von Operatoren, die Sie für allgemeine Operationen einsetzen können. Werden zwei Zahlen dividiert, müssen Sie sich keine Gedanken darüber machen, welcher Code im Hintergrund vom Compiler erzeugt wird:

double ergebnis = value1 / value2;

Die Frage nach dem Typ der Operanden ist nicht bedeutungslos. Handelt es sich um ganzzahlige Typen, wird ein anderes Kompilat erzeugt, als würde es sich um zwei Dezimalzahlen handeln. Abhängig vom Typ der Operanden werden intern zwei unterschiedliche Operationen ausgeführt. Der Compiler entscheidet darüber, um welche Operation es sich dabei handelt, denn der /-Operator ist überladen. Insbesondere für die elementaren Datentypen wie int, long, double usw. sind die meisten Operatoren überladen.

Eine der großen Stärken von C# ist, dem Entwickler das Instrumentarium an die Hand zu geben, um im Bedarfsfall Operatoren nach eigenem Ermessen zu überladen.


Rheinwerk Computing - Zum Seitenanfang

10.6.2 Die Syntax der OperatorüberladungZur nächsten ÜberschriftZur vorigen Überschrift

Um Operatoren in einer Klasse oder einer Struktur zu überladen, stellt C# das Schlüsselwort operator zur Verfügung, das nur in Verbindung mit public static verwendet werden darf. Hinter dem operator-Schlüsselwort wird der Operator angegeben, der überladen werden soll. Die folgende Syntax gilt für binäre Operatoren, die zwei Operanden für ihre Operation benötigen:

public static <Ergebnistyp> operator <Operator> (<Operand1>, <Operand2>)

Neben den binären gibt es auch unäre Operatoren, die nur einen Operanden verlangen. Stellvertretend seien hier die Operatoren »++« und »--« genannt. Für diese Operatorengruppe ändert sich die Syntax wie folgt:

public static <Ergebnistyp> operator <Operator> (<Operand>)

Wenn Sie eine Klasse um Methoden zur Operatorüberladung erweitern, sollten Sie folgende Punkte berücksichtigen:

  • Es können nur vordefinierte Operatoren überladen werden. Neue Operatoren zu »erfinden« ist nicht möglich.
  • Die Operationen von Operatoren auf den elementaren Datentypen können nicht umdefiniert werden.
  • Die Grundfunktionalität eines Operators bleibt immer erhalten: Ein binärer Operator benötigt immer zwei Operanden, ein unärer immer nur einen. Die Vorrangregeln können nicht beeinflusst werden.

In Tabelle 10.1 sind alle Operatoren aufgeführt, die in einer Klasse oder Struktur überladen werden dürfen.

Tabelle 10.1 Überladbare Operatoren

C#-Operator Bedeutung

+, -, !, ~, ++, --, true, false

Unäre Operatoren

+, -, *, /, %, &, |, ^, <<, >>

Binäre Operatoren

==, !=, <, >, <=, >=

Relationale Operatoren

[]

Dieser Operator kann eigentlich nicht überladen werden. Es gibt jedoch ein Ersatzkonstrukt (Indexer), das die gleiche Funktionalität bietet (siehe Abschnitt 10.7).

Einige Operatoren können nur paarweise überladen werden. Wollen Sie zum Beispiel den Vergleichsoperator »==« überladen, müssen Sie auch den Operator »!=« überladen. Damit erzwingt C# eine konsistente Prüfung auf Übereinstimmung und Nichtübereinstimmung.

Einschränkungen der Operatorüberladung

Nicht alle Operatoren sind überladungsfähig. Ausgeschlossen ist unter anderem auch der Zuweisungsoperator »=«. Überladen Sie einen binären Operator, z. B. »+«, wird der Additionszuweisungsoperator »+=« automatisch implizit überladen.

Zu den anderen nichtüberladbaren Operatoren gehören der Punktoperator, der bedingte Operator »?:« sowie die Operatoren new, is, typeof und sizeof. Ebenso wenig überladbar sind die runden Klammern, mit denen eine Typkonvertierung durchgeführt wird. Stattdessen sollten benutzerdefinierte Konvertierungen codiert werden. Dieses Thema beschäftigt uns weiter unten.


Rheinwerk Computing - Zum Seitenanfang

10.6.3 Die Operatorüberladungen im Projekt »GeometricObjectsSolution«Zur nächsten ÜberschriftZur vorigen Überschrift

Wir wollen uns die Operatorüberladung jetzt an einem Beispiel ansehen. Dazu rufen wir uns die Methode Bigger der Klasse GeometricObject in Erinnerung:

public static int Bigger(GeometricObject object1, GeometricObject object2)
{
if (object1 == null || object2 == null) return 0;
if (object1 == null) return -1;
if (object2 == null) return 1;
if (object1.GetArea() > object2.GetArea()) return 1;
if (object1.GetArea() < object2.GetArea()) return -1;
return 0;
}

Listing 10.18 Die Methode »Bigger« der Klasse »GeometricObject«

Übergeben wir zwei Circle-Objekte, können wir zweifelsfrei feststellen, welches der beiden größer ist als das andere, z. B.:

if(GeometricObject.Bigger(kreis1, kreis2) == 1) [...]

Selbstkritisch müssen wir aber auch feststellen, dass der gleichwertige Ausdruck

if(kreis1 > kreis2)

eher einer üblichen Vergleichsoperation entspricht. Bisher ist diese Vergleichsoperation jedoch nicht möglich, weil sie für Objekte vom Typ der Basisklasse GeometricObject oder in einer der abgeleiteten Klassen nicht definiert ist. Um dieses Defizit auszugleichen, wollen wir jetzt den >-Operator so überladen, dass er zur Laufzeit auf zwei Objekte vom Typ GeometricObject angewendet werden kann. Dabei müssen wir berücksichtigen, dass einer der beiden Operanden null sein könnte. In diesem Fall ist es üblich, eine Ausnahme auszulösen.

public static bool operator >(GeometricObject object1,
GeometricObject object2)
{
if (object1 == null || object2 == null)
throw new InvalidOperationException();
return object1.GetArea() > object2.GetArea() ? true: false;
}

Listing 10.19 Überladen des »>«-Operators

Kompilieren wir die so ergänzte Klassendefinition, erhalten wir einen Compilerfehler, weil sich ein GeometricObject-Objekt jetzt nicht mehr eindeutig verhält. Wir werden gezwungen, einen weiteren Vergleichsoperator zu überladen, nämlich den, der die Umkehrung der bereits überladenen Vergleichsfunktion beschreibt.

public static bool operator <(GeometricObject object1,GeometricObject object2) {
if (object1 == null || object2 == null)
throw new InvalidOperationException();
return object1.GetArea() < object2.GetArea()? true: false;
}

Listing 10.20 Überladen des »<«-Operators

Nach dem anschließenden erfolgreichen Kompilieren können wir mit

Circle kreis1 = new Circle(6);
Circle kreis2 = new Circle(3);
if(kreis1 > kreis2) {
[...]
}

alternativ zu der von uns implementierten Methode Bigger Vergleichsoperationen mit Objekten unserer Klasse ausführen. Da die Überladung für alle Objekte vom Typ GeometricObject gilt, lässt sich auch ein Circle mit einem Rectangle vergleichen.

Überladen von Gleichheitsoperatoren

Im Abschnitt zuvor haben wir die Operatoren »<« und »>« überladen, um die Größe zweier geometrischer Objekte miteinander zu vergleichen. Vielleicht ist Ihnen aufgefallen, dass bisher der Vergleich mit dem ==-Operator nicht bereitgestellt worden ist. Das wollen wir nun tun. Dazu muss ich ein wenig ausholen, denn die Lösung der Problematik ist nicht ganz trivial.

Jede Klasse beerbt die Klasse Object. Damit hat jedes Objekt die Methoden, die in Object definiert sind. Zu diesen Methoden gehört auch die Methode Equals, mit der von Hause aus zwei Referenzen auf Gleichheit hin untersucht werden können. Das wollen wir uns an einem kleinen Beispiel zuerst ansehen:

Circle kreis1 = new Circle(12);
Circle kreis2 = kreis1;
if(kreis1.Equals(kreis2))
Console.WriteLine("Referenzielle Gleichheit");
else
Console.WriteLine("Zwei verschiedene Objekte");

Listing 10.21 Referenzen auf Gleichheit mit »Equals« hin prüfen

Verweisen beide Referenzen auf dasselbe Objekt, liefert die Equals-Methode als Rückgabewert true. Das ist das Standardverhalten dieser Methode. In gleicher Weise arbeitet auch der »==«-Vergleichsoperator. Wir könnten demnach die if-Anweisung auch wie folgt formulieren:

if(kreis1 == kreis2)
[...]

Der Vergleichsoperator »==« soll laut Definition die Syntax für den Vergleich mit Equals vereinfachen. Wird der Vergleichsoperator überladen, muss er von der Logik her mit Equals übereinstimmen. Der C#-Compiler gibt sogar eine Warnmeldung aus, wenn gegen diese Regel verstoßen wird.

Da es unser Ziel ist, den Vergleichsoperator »==« zu überladen, dürfen wir das Überschreiben der virtuellen Equals-Methode nicht vergessen. Und selbstverständlich gilt es auch, den Vergleich mit »!=« zu implementieren.

Widmen wir unser Augenmerk zuerst der Überladung des Operators »==«. Die wird dabei wie folgt definiert:

public static bool operator ==(GeometricObject obj1,GeometricObject obj2)

Jetzt müssen wir mehrere Situationen betrachten:

  • Die beiden Parameter obj1 und obj2 verweisen auf dasselbe Objekt. Der Vergleich liefert dann den Rückgabewert true.
  • Entweder obj1 oder obj2 wird durch null beschrieben. Dann sollte der Rückgabewert in jedem Fall false sein.
  • Trifft keiner der vorgenannten Punkte zu, erfolgt der Vergleich anhand der Methode GetArea.

Widmen wir uns dem ersten Punkt. Um einen Referenzvergleich anstellen zu können, kommt die Methode Equals nicht mehr in Betracht, da wir sie später überschreiben müssen. Eine andere Möglichkeit liefert uns die statische Methode ReferenceEquals der Klasse Object, die wie folgt definiert ist:

public static bool ReferenceEquals(Object object1, Object object2)

Der Rückgabewert dieser Methode ist true, wenn es sich bei object1 und object2 um dieselbe Instanz handelt. Wird an einen der beiden Parameter aber null übergeben, ist der Rückgabewert false.

Mit dieser Erkenntnis können wir den Vergleichsoperator »==« nun wie im Listing 10.22 gezeigt überladen:

public static bool operator ==(GeometricObject obj1, GeometricObject obj2)
{
if (ReferenceEquals(obj1, obj2)) return true;
if (ReferenceEquals(obj1, null)) return false;
return obj1.Equals(obj2);
}

Listing 10.22 Überladen des »==«-Operators

In der Überladung wird Equals aufgerufen. Die Idee, die sich dahinter verbirgt, ist, dass in Equals der tatsächliche Größenvergleich durchgeführt werden soll, also:

public override bool Equals(object @object)
{
if (@object == null) return false;
if (GetArea() == ((GeometricObject)@object).GetArea()) return true;
return false;
}

Listing 10.23 Überschreiben der Methode »Equals«

Vielleicht stellen Sie sich die Frage, warum in der ersten Anweisung noch einmal eine Überprüfung auf null stattfindet, die doch eigentlich bereits in der Operatorüberladungsmethode durchgeführt worden ist. Aber vergessen Sie nicht, dass Equals auch unabhängig von der Nutzung des überladenen Vergleichsoperators auch auf eine GeometricObject-Referenz aufgerufen werden könnte. Was uns nun noch fehlt, ist die Überladung des !=-Operators. Aber das ist nun wirklich keine schwierige Aufgabe mehr.

public static bool operator !=(GeometricObject obj1, GeometricObject obj2)
{
return !(obj1 == obj2);
}

Listing 10.24 Überladung des »!=«-Operators

Starten Sie mit diesen Ergänzungen und dem folgenden Testcode die Anwendung.

static void Main(string[] args) {
Circle kreis1 = new Circle(2);
Circle kreis2 = new Circle(1);
kreis1 = null;
if (kreis1 == kreis2)
Console.WriteLine("k1 == k2");
else
Console.WriteLine("k1 != k2");
Console.ReadLine();
}

Listing 10.25 Testen der überladenen Operatoren »==« und »!=«

Sie werden feststellen, dass die Operatorüberladungen das tun, was wir von ihnen erwarten. Allerdings gibt es noch einen kleinen Wermutstropfen, denn wir erhalten einen Warnhinweis, der besagt, dass im Falle eines Überschreibens der Equals-Methode auch die von der Klasse Object geerbte Methode GetHashCode überschrieben werden muss, damit der Typ in einer Hashtabelle korrekt funktioniert.

public override int GetHashCode() {
return base.GetHashCode();
}

Listing 10.26 Überschreiben der Methode »GetHashCode«

Sie finden das komplette Beispielprojekt GeometricObjectsSolution auf der Buch-DVD unter ..\Kapitel 10\GeometricObjectsSolution_10.

Die Klasse GeometricObject ist im Projekt der Vollständigkeit halber auch noch um die Überladung der Operatoren »<=« und »>=« ergänzt worden.

Überladene Operatoren in der Vererbung

Wird aus einer Klasse, die Operatoren überlädt, eine weitere Klasse abgeleitet, vererben sich die überladenen Operatoren an die abgeleitete Klasse. In unserem Beispielprojekt werden somit die Klassen Circle und Rectangle von den Operatorüberladungen profitieren können.


Rheinwerk Computing - Zum Seitenanfang

10.6.4 Die Operatoren »true« und »false« überladenZur nächsten ÜberschriftZur vorigen Überschrift

Wenn Sie Tabelle 10.1 aufmerksam studiert haben, werden Ihnen vielleicht zwei ungewöhnlich erscheinende, überladungsfähige Operatoren aufgefallen sein: true und false. Diese dienen dazu, Operationen wie beispielsweise

if (@object)
[...]

zu ermöglichen. Diese Bedingungsprüfung ist sinnvoll, wenn der Rückgabewert direkt von einem Feld abhängt. Soll außerdem auch noch der Negationsoperator berücksichtigt werden, muss auch der !-Operator überladen werden.

if(!@object)
[...]

Die Operatoren true und false gehören ebenfalls zu der Gruppe der Operatoren, die man paarweise überladen muss. Die Rückgabe ist ein boolescher Wert. Im folgenden Beispiel wird die Überladung der drei Operatoren »true«, »false« und »!« gezeigt. Dazu wird festgelegt, dass ein Objekt dann als true zu bewerten ist, wenn der Inhalt des objektspezifischen Felds ungleich 0 ist.

// Beispiel: ..\Kapitel 10\Operatorüberladung_True_False
class Program {
static void Main(string[] args)
{
Demo obj = new Demo { Value = 12 };
obj.Value = 8;
if(obj)
Console.Write("Wert ungleich 0");
else
Console.Write("Wert gleich 0");
Console.ReadLine();
}
}
// Klasse Demo
class Demo {
public int Value { get; set;}
// Überladung des true-Operators
public static bool operator true(Demo @object) {
return @object.Value != 0 ? true : false;
}
// Überladung des false-Operators
public static bool operator false(Demo obj) {
return obj.Value != 0 ? false : true;
}
// Überladung des Negationsoperators
public static bool operator !(Demo obj) {
return obj.Value != 0 ? false : true;
}
}

Listing 10.27 Das Beispielprogramm »Operatorüberladung_True_False«

Die dem Feld zugewiesene Zahl 12 wird mit

if (obj)

zu der Anzeige

Wert ungleich 0

führen. Benutzen wir im Ausdruck den !-Operator, kehrt sich die Logik um und führt zu folgender Ausgabe:

Wert gleich 0

Rheinwerk Computing - Zum Seitenanfang

10.6.5 Benutzerdefinierte KonvertierungenZur nächsten ÜberschriftZur vorigen Überschrift

Implizite benutzerdefinierte Konvertierung

Stellen Sie sich vor, Sie hätten die Klasse Demo folgendermaßen definiert:

public class Demo {
public int Value { get; set; }
}

Demo enthält nur ein Integer-Feld. Diese Definition könnte dazu verleiten, eine Referenz der Klasse Demo einer int-Variablen wie folgt zuzuweisen:

Demo obj = new Demo { Value = 10 };
int x = obj;

Selbstverständlich wird es nur bei einem Versuch bleiben, denn der Compiler stellt eine unzulässige Konvertierung des Demo-Typs in einen int fest und macht das Unterfangen zunichte.

C# bietet uns die Möglichkeit, bestimmte Typkonvertierungen zu gestatten. Angenommen, unser Ziel sei es, das Codefragment tatsächlich einwandfrei zu kompilieren. Dazu müssen wir die Klasse wie folgt um die Definition einer benutzerdefinierten Konvertierung erweitern:

public class Demo {
public int Value { get; set; }
public static implicit operator int(Demo @object) {
return @object.Value;
}
}

Listing 10.28 Benutzerdefinierte Konvertierung

Sehen wir uns den Methodenkopf genauer an. Im Vergleich zu einer Methode, die einen Operator überlädt, ist die Definition der Methode zur Typkonvertierung um das neue Schlüsselwort implicit ergänzt worden. Den Schlüsselwörtern implicit operator folgt der Datentyp, in den implizit konvertiert wird. In unserem Beispiel ist es int. Der Parameter definiert den Typ, der konvertiert werden soll.

Die allgemeine Syntax der impliziten benutzerdefinierten Typkonvertierung lautet:

public static implicit operator <Zieldatentyp>(<Eingabetyp>)

Die Aussage in unserem Beispiel ist also die folgende: Konvertiere ein Objekt vom Typ Demo implizit in einen Integer.

Benutzerdefinierte Konvertierungen liefern ein Ergebnis: Es ist genau von dem Typ, der hinter operator angegeben wird. Im Anweisungsblock der Konvertierungsmethode muss deshalb ein return-Statement, gefolgt vom entsprechenden Rückgabewert, angegeben werden – in unserem Fall der Inhalt des Feldes Value des Objekts, dessen Referenz die Methode im Parameter @object empfängt.

Weil ein int vom System implizit in den Datentyp long konvertiert wird, wird jetzt auch das folgende Listing fehlerfrei kompiliert:

Demo @object = new Demo();
@object.Value = 1;
long x = @object;

Listing 10.29 Die benutzerdefinierte Konvertierung nutzen

Explizite benutzerdefinierte Konvertierung

Eine implizite Konvertierung sollte nur in Betracht gezogen werden, wenn bei einer Konvertierung keine Daten verloren gehen. Nehmen wir nun an, die Klasse Demo sei etwas anspruchsvoller:

public class Demo {
public int Value { get; set; }
public string Text { get; set; }
}

Wir wollen wieder sicherstellen, dass die Referenz auf ein Demo-Objekt in einen Integer konvertiert werden kann. Dazu könnten wir auch hier eine implizite benutzerdefinierte Konvertierung anbieten. Tatsache ist aber, dass uns bei der Typumwandlung Informationen verloren gehen, auch wenn diese vom empfangenden Element nicht benötigt werden. Im Beispiel ist es das Feld vom Typ string. Wenn Sie Wert auf eine stilistisch saubere Programmierung legen, sollten Sie eine explizite Konvertierung vorschreiben. Sie vermeiden dadurch außerdem, dass eine implizite Konvertierung automatisch ausgeführt wird, ohne dass der Aufrufer sie gewünscht hat.

Um eine benutzerdefinierte, explizite Typumwandlung zu implementieren, muss das Schlüsselwort explicit in der Methodensignatur angegeben werden. Ansonsten ähnelt die Syntax der der impliziten benutzerdefinierten Konvertierung:

public static explicit operator <Zieldatentyp>(<Eingabedatentyp>)

Sehen wir uns dazu das vollständige Beispiel an:

public class Demo {
public int Value { get; set; }
public string Text { get; set; }
public static explicit operator int(Demo @object) {
return @object.Value;
}
public static explicit operator string(Demo @object) {
return @object.Text;
}
}

Listing 10.30 Benutzerdefinierte explizite Typkonvertierung

Demo beschreibt nun sogar zwei explizite Konvertierungen: in einen int und in einen string. Programmcode, der ein Demo-Objekt einem Integer zuweisen möchte, würde jetzt zu einer expliziten Konvertierung gezwungen, z. B.:

Demo obj = new Demo { Value = 10, Text = "Hallo" };
int x = (int)obj;

Analog lässt sich mit der Anweisung

string str = (string)obj;

eine Referenz vom Typ Demo auch einer string-Variablen zuweisen.

Das gleichzeitige Implementieren einer expliziten und einer impliziten Konvertierungsfunktion mit demselben Zieldatentyp ist unzulässig.

Konvertierungen Im Projekt »GeometricObjects«

Ich weiß, es ist ein wenig »an den Haaren herbeigezogen«, aber lassen Sie uns trotzdem die beiden Klassen Circle und Rectangle um benutzerdefinierte Konvertierungen erweitern: Dabei soll ein Circle-Objekt einer Rectangle-Referenz zugewiesen werden können und umgekehrt. Beide Konvertierungen sollen als explizite Konvertierungen bereitgestellt werden.

Sehen wir uns zuerst die Konvertierung eines Circle-Objekts in ein Rechteck an. Dabei muss zuvor eine Vereinbarung getroffen werden: Da das Verhältnis von Breite zu Länge des Rechtecks unbestimmbar ist, soll das Ergebnis der Konvertierung ein Quadrat sein, also der Sonderfall eines Rechtecks. Hierbei soll es sich um das Quadrat handeln, in dem das Circle-Objekt so eingebettet ist, dass es die vier Kanten des Quadrats innen berührt. Berücksichtigen sollten wir dabei auch, dass der Bezugspunkt des Kreises gleichzeitig dessen Mittelpunkt ist, während das Rechteck (bzw. das Quadrat) seinen Bezugspunkt auf der linken oberen Ecke definiert.

public class Circle {
[...]
public static explicit operator Rectangle(Circle circle) {
return new Rectangle(2 * circle.Radius, 2 * circle.Radius,
circle.XCoordinate - circle.Radius,
circle.YCoordinate - circle.Radius);
}
}

Listing 10.31 Explizite Konvertierung eines »Circle«-Objekts in den Typ »Rectangle«

Etwas schwieriger gestaltet sich die Konvertierung eines Rechtecks in einen Kreis. Wir müssen zuerst die Fläche des Rechtecks ermitteln, um basierend auf der Fläche einen Radius für das Circle-Objekt zu berechnen. Wegen der Konvertierung eines double in einen int wird das Ergebnis natürlich an Genauigkeit verlieren.

Den Mittelpunkt des Kreises verschieben wir auf den Schnittpunkt der Diagonalen des Rechtecks.

public class Rectangle 
{
[...]
public static explicit operator Circle(Rectangle rect) {
int radius = (int)Math.Sqrt(rect.GetArea() / Math.PI);
return new Circle(radius, rect.Length/2, rect.Width/2);
}
}

Listing 10.32 Explizite Konvertierung eines »Rectangle«-Objekts in einen »Circle«

Nun wollen wir das Ergebnis noch mit dem folgenden Code testen.

static void Main(string[] args)
{
Circle kreis = new Circle(100, 100, 100);
Rectangle rect = (Rectangle)kreis;
Console.WriteLine("Length|Width = {0}, X = {1}, Y = {2}",
rect.Length, rect.XCoordinate, rect.YCoordinate);
Rectangle rect1 = new Rectangle(100, 50);
Circle kreis1 = (Circle)rect1;
Console.WriteLine("Radius = {0}, X = {1}, Y = {2}",
kreis1.Radius, kreis1.XCoordinate, kreis1.YCoordinate);
Console.ReadLine();
}

Listing 10.33 Hauptprogramm zum Testen der expliziten Konvertierung

Auf der Buch-DVD finden Sie die Ergänzung des Projekts GeometricObjectSolution unter ..\Kapitel 10\GeometricObjectsSolution_11.



Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Visual C# 2012

Visual C# 2012
Jetzt Buch bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Rheinwerk-Shop: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: C/C++






 C/C++


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo





Copyright © Rheinwerk Verlag GmbH 2013
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern