Galileo Computing < openbook > Galileo 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

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 6 Strukturen und Enumerationen
Pfeil 6.1 Strukturen – eine Sonderform der Klassen
Pfeil 6.1.1 Die Definition einer Struktur
Pfeil 6.1.2 Initialisieren einer Strukturvariablen
Pfeil 6.1.3 Konstruktoren in Strukturen
Pfeil 6.1.4 Änderung im Projekt »GeometricObjects«
Pfeil 6.2 Enumerationen (Aufzählungen)
Pfeil 6.2.1 Wertzuweisung an enum-Mitglieder
Pfeil 6.2.2 Alle Mitglieder einer Aufzählung durchlaufen
Pfeil 6.3 Boxing und Unboxing

6 Strukturen und EnumerationenZur nächsten Überschrift


Galileo Computing - Zum Seitenanfang

6.1 Strukturen – eine Sonderform der KlassenZur nächsten ÜberschriftZur vorigen Überschrift

.NET stellt mit der Struktur ein Konstrukt bereit, das einer Klasse sehr ähnlich ist. Strukturen gehören zur Gruppe der Wertetypen und werden somit nicht im Heap, sondern auf den Stack gespeichert.

Strukturen werden meistens dann eingesetzt, wenn sehr viele Objekte eines bestimmten Typs erwartet werden können. Nehmen wir dazu beispielsweise an, Sie beabsichtigen, jedes Pixel des Monitors durch ein Objekt zu beschreiben. Selbst bei einer »Standardauflösung« von 1.024 x 768 würde man 786.432 Objekte benötigen. Das ist schon eine Zahl, bei der man sich Gedanken darüber machen sollte, ob anstatt einer Klasse nicht eine Strukturdefinition die hohen Speicher- und Performanceanforderungen besser erfüllen könnte. Denn im Gegensatz zu klassenbasierten Objekten, für die ein verhältnismäßig hoher Verwaltungsaufwand notwendig ist, beanspruchen strukturbasierte Objekte, die zu den Wertetypen gerechnet werden, relativ wenige Verwaltungsressourcen und sind deshalb performancetechnisch deutlich besser.


Galileo Computing - Zum Seitenanfang

6.1.1 Die Definition einer StrukturZur nächsten ÜberschriftZur vorigen Überschrift

Stellen Sie sich vor, Sie möchten eine Person durch eine Klassendefinition beschreiben. Eine Person sei durch ihren Namen und das Alter gekennzeichnet. Außerdem soll die Klasse die Methode Run veröffentlichen. Die Klassendefinition könnte folgendermaßen lauten:

public class Person {
public string Name { get; set; }
public int Age { get; set; }

public void Run() {
[...]
}
}

Listing 6.1 Definition einer Klasse »Person«

Tatsächlich unterscheidet sich die analoge Definition des Typs Person durch eine Struktur kaum von der einer Klasse – abgesehen vom Austausch des Schlüsselwortes class durch struct:

public struct Person {
[...]
}

Listing 6.2 Definition der Struktur »Person«

Im ersten Moment mag das zu der ersten Schlussfolgerung verleiten, man könne eine komplette Klasse gleichwertig durch eine Struktur ersetzen, denn Strukturen können Eigenschaften, Methoden und auch Ereignisse definieren, Schnittstellen implementieren und Methoden nach den bekannten Regeln überladen. Es gibt jedoch auch ein paar Einschränkungen, die in Kauf genommen werden müssen, wenn Sie sich anstelle einer Klasse für eine Struktur entscheiden:

  • Eine Struktur kann nicht aus einer beliebigen Klasse abgeleitet werden. Grundsätzlich ist ValueType die Basisklasse aller Strukturen. ValueType selbst ist direkt von Object abgeleitet.
  • Eine Struktur kann nicht abgeleitet werden.
  • Strukturen besitzen immer einen parameterlosen Konstruktor, der auch nicht überschrieben werden darf.
  • Felder dürfen nicht mit einem Wert vorinitialisiert werden. Damit würde die folgende Strukturdefinition zu einem Fehler führen:
    struct Person {
    private int Age = 0;
    [...]
    }

Galileo Computing - Zum Seitenanfang

6.1.2 Initialisieren einer StrukturvariablenZur nächsten ÜberschriftZur vorigen Überschrift

Wäre der Typ Person als Klasse definiert, müsste vor dem ersten Aufruf eine Instanz durch das Aufrufen des Operators new erzeugt werden:

// Annahme: Person liegt als class-Definition vor

Person pers = new Person();
pers.Age = 34;

Eine Struktur wird demgegenüber von der Laufzeitumgebung jedoch wie die Variable eines elementaren Datentyps eingesetzt, da kein Verweis damit verknüpft ist. Der Zugriff auf die Elemente einer Struktur erfolgt ebenfalls mit dem Punktoperator.

// Person liegt als struct-Definition vor

Person pers = new Person();
pers.Name = "Willi Jakob";
pers.Age = 34;

Die Eigenschaften Name und Age sind einem ganz bestimmten Element zugeordnet, nämlich pers. Das erinnert an die Instanzvariablen einer Klasse. Der Vergleich ist auch nicht falsch, denn eine Strukturvariable ist einem Objektverweis sehr ähnlich und deutet darauf hin, dass es innerhalb einer Struktur einen Konstruktor geben muss, der parameterlos ist. Mit new wird dieser Konstruktor aufgerufen, der – wie auch der Konstruktor einer Klasse – die Felder des Objekts initialisiert.

Vereinfachte Initialisierung

Eine abweichende, einfachere Initialisierung eines Strukturtyps ist unter Umständen ebenfalls möglich. Nehmen wir an, die Klasse Person wäre folgendermaßen implementiert:

struct Person {
public string Name;
public int Age;
}

Nun lässt sich ein Objekt vom Typ Person auch ohne Angabe des Konstruktors erstellen, z. B.:

Person pers;
pers.Name = "Hans";

Dabei ist aber Vorsicht angesagt. Dem Feld Name wird in diesem Fall ausdrücklich ein Wert zugewiesen. Damit ist es auch initialisiert. Das Feld Age hingegen ist noch nicht initialisiert, denn es wird schließlich auch kein Konstruktor aufgerufen. Der Zugriff auf ein nichtinitialisiertes Feld mündet in einen Fehler.

Sie können ohne den Operator new ein Objekt erzeugen, wenn die Struktur ausschließlich Felder hat (automatisch implementierte Eigenschaften zählen nicht zu den Feldern) und keine Methoden. Enthält die Struktur jedoch Methoden, müssen zuerst alle Felder initialisiert werden, um die Methoden des Objekts fehlerfrei aufrufen zu können.


Galileo Computing - Zum Seitenanfang

6.1.3 Konstruktoren in StrukturenZur nächsten ÜberschriftZur vorigen Überschrift

Standardmäßig stellt eine Struktur einen parameterlosen Konstruktor bereit, der mit

Person pers = new Person();

aufgerufen werden kann. Strukturen lassen die Definition weiterer Konstruktoren zu, die jedoch parametrisiert sein müssen, denn das Überschreiben des parameterlosen Konstruktors einer Struktur ist nicht erlaubt. Fügen Sie einen parametrisierten Konstruktor hinzu, muss eine Bedingung erfüllt werden: Alle Felder der Struktur müssen initialisiert werden. Im folgenden Listing wird das gezeigt:

public struct Person {
public string Name { get; set; }
public int Age { get; set; }

// Konstruktor

public Person(string name) {
Age = 0;
Name = name;
}
}

Listing 6.3 Konstruktor in einer Struktur

Der Aufruf eines parametrisierten Konstruktors führt nur über den new-Operator. Vorsicht ist hierbei geboten, denn das folgende Codefragment hat die doppelte Initialisierung der Variablen pers zur Folge, weil in der zweiten Anweisung ein parametrisierter Konstruktor aufgerufen wird:

Person pers;
pers = new Person("Willi");

Läge Person eine Klasse zugrunde, würde es nur zu einem Konstruktoraufruf kommen.


Galileo Computing - Zum Seitenanfang

6.1.4 Änderung im Projekt »GeometricObjects«Zur vorigen Überschrift

Wir wollen uns nun erneut der Anwendung GeometricObjectsSolution zuwenden. An einer Stelle bietet es sich an, eine Struktur einzusetzen: Es handelt sich dabei um die beiden Mittelpunktskoordinaten XCoordinate und YCoordinate, die in der Klasse GeometricObject definiert sind und nun durch die Struktur Point ersetzt werden sollen. Der Typ Point ist sehr einfach aufgebaut und hat nur zwei Eigenschaften, die später den Bezugspunkt des geometrischen Objekts beschreiben sollen. Selbstverständlich werden die entsprechenden Felder auch gekapselt, d. h. über die Kombination der beiden Accessoren get und set veröffentlicht. Außerdem enthält die Struktur einen zweiparametrigen Konstruktor, dem beim Aufruf die Punktkoordinaten übergeben werden.

public struct Point {

// Felder

private double _X;
private double _Y;

// Eigenschaften

public double X {
get { return _X; }
set { _X = value; }
}

public double Y {
get { return _Y; }
set { _Y = value; }
}

// Konstruktor

public Point(double x, double y) {
_X = x;
_Y = y;
}
}

Listing 6.4 Komplette Definition der Struktur »Point«

In der Klasse GeometricObject zieht das selbstverständlich Änderungen nach sich. Wir definieren zuerst ein Feld vom Typ der Struktur. Dieses soll in der überarbeiteten Fassung die Werte des Bezugspunktes aufnehmen.

protected Point _Center = new Point();

Dabei sollte explizit der parameterlose Konstruktor aufgerufen werden, damit X und Y im Feld _Center von Anfang an initialisiert sind und einen definierten Anfangszustand haben.

Einen wichtigen Punkt dürfen wir an dieser Stelle nicht außer Acht lassen. Da wir nun mit dem Feld _Center eine Point-Struktur eingeführt haben, die die Werte von XCoordinate und YCoordinate speichern soll, müssen wir die beiden noch vorhandenen privaten Felder _XCoordinate und _YCoordinate aus der Klasse GeoemtricObject löschen. Darüber hinaus gilt es, die beiden Eigenschaften XCoordinate und YCoordinate so anzupassen, dass die den Eigenschaften übergebenen Werte an die Felder der Point-Struktur übergeben bzw. daraus ausgelesen werden.

public virtual double XCoordinate {
get { return _Center.X; }
set {
_Center.X = value;
OnPropertyChanged("XCoordinate");
}
}

public virtual double YCoordinate {
get { return _Center.Y; }
set {
_Center.Y = value;
OnPropertyChanged("YCoordinate");
}
}

Listing 6.5 Änderung der Eigenschaften »XCoordinate« und »YCoordinate«

Von der Einführung der Struktur Point sind auch die Konstruktoren von Circle und Rectangle betroffen, die die beiden Mittelpunktskoordinaten in ihren Parametern erwarten.

public Circle(int radius, double x, double y) {
Radius = radius;
_Center.X = x;
_Center.Y = y;
Circle._CountCircles++;
}

public Rectangle(int length, int width, double x, double y) {
Length = length;
Width = width;
_Center.X = x;
_Center.Y = y;
Rectangle._CountRectangles++;
}

Listing 6.6 Änderung der Konstruktoren in »Circle« und »Rectangle«

Eine gute Klassendefinition zeichnet sich nicht nur dadurch aus, dass sie die Implementierung auf das Notwendigste beschränkt, sondern deckt auch die Fälle ab, die für einen Benutzer unter Umständen sinnvoll sein könnten. Soll der Mittelpunkt eines Kreisobjekts diagonal verschoben werden, sind zwei Anweisungen notwendig. Vorteilhafter ist es, dasselbe mit einer Anweisung zu erreichen. Die Verbesserung soll durch eine Methode erzielt werden, die wir als Move bezeichnen. Sie nimmt ein Point-Objekt vom Aufrufer entgegen und wird in GeometricObject definiert.

public virtual void Move(Point center) {
_Center = center;
}

Da eine Struktur ein Wertetyp ist, schreiben sich die Felder X und Y der im Parameter center übergebenen Koordinaten in die gleichlautenden Felder von _Center.

Sehen wir uns nun in einem Codefragment an, wie einfach es ist, diese Methode zu benutzen. Es wird dabei davon ausgegangen, dass ein konkretes Circle-Objekt namens kreis vorliegt. Mit

Point pt = new Point(150, 315);
kreis.Move(pt);

übergeben wir der Methode ein Point-Objekt. Benötigen wir dieses Objekt zur Laufzeit der Anwendung nicht mehr, kann es auch in der Argumentenliste erzeugt werden.

kreis.Move(new Point(150, 315)); 

Zuletzt ergänzen wir die Klassen Circle und Rectangle noch um einen Konstruktor, der neben dem Radius bzw. den entsprechenden Längenangaben eine Point-Referenz als Argument erwartet:

public Circle(int radius, Point center) {
Radius = radius;
_Center = center;
Circle._CountCircles++;
}

public Rectangle(int length, int width, Point center) {
Length = length;
Width = width;
_Center = center;
Rectangle._CountRectangles++;
}

Listing 6.7 Zusätzliche Konstruktoren in »Circle« und »Rectangle«

Da bei Aufruf dieses Konstruktors kein weiterer der Klasse ausgeführt wird, ist es auch notwendig, den Objektzähler der jeweiligen Klasse zu erhöhen.

Damit wird eine Instanziierung der Klasse Circle beispielsweise mit

Circle kreis = new Circle(2, new Point(5, 12));

möglich.

Den Code des Beispiels GeometricObjectsSolution mit allen Änderungen, die wir bisher in diesem Kapitel vorgenommen haben, finden Sie auf der Buch-DVD unter ...\Kapitel 6\GeometricObjectsSolution_7.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück
  Zum Katalog
Zum Katalog: Visual C# 2012

Visual C# 2012
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Katalog: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Katalog: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Katalog: C++ Handbuch






 C++ Handbuch


Zum Katalog: C/C++






 C/C++


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
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.


[Rheinwerk Computing]

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