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 3 Das Klassendesign
Pfeil 3.1 Einführung in die Objektorientierung
Pfeil 3.2 Die Klassendefinition
Pfeil 3.2.1 Klassen im Visual Studio anlegen
Pfeil 3.2.2 Das Projekt »GeometricObjectsSolution«
Pfeil 3.2.3 Die Deklaration von Objektvariablen
Pfeil 3.2.4 Zugriffsmodifizierer einer Klasse
Pfeil 3.2.5 Splitten einer Klassendefinition mit »partial«
Pfeil 3.2.6 Arbeiten mit Objektreferenzen
Pfeil 3.3 Referenz- und Wertetypen
Pfeil 3.3.1 Werte- und Referenztypen nutzen
Pfeil 3.4 Die Eigenschaften eines Objekts
Pfeil 3.4.1 Öffentliche Felder
Pfeil 3.4.2 Datenkapselung mit Eigenschaftsmethoden sicherstellen
Pfeil 3.4.3 Die Ergänzung der Klasse »Circle«
Pfeil 3.4.4 Lese- und schreibgeschützte Eigenschaften
Pfeil 3.4.5 Sichtbarkeit der Accessoren »get« und »set«
Pfeil 3.4.6 Unterstützung von Visual Studio 2012
Pfeil 3.4.7 Automatisch implementierte Eigenschaften
Pfeil 3.5 Methoden eines Objekts
Pfeil 3.5.1 Methoden mit Rückgabewert
Pfeil 3.5.2 Methoden ohne Rückgabewert
Pfeil 3.5.3 Methoden mit Parameterliste
Pfeil 3.5.4 Methodenüberladung
Pfeil 3.5.5 Variablen innerhalb einer Methode (lokale Variablen)
Pfeil 3.5.6 Referenz- und Wertparameter
Pfeil 3.5.7 Besondere Aspekte einer Parameterliste
Pfeil 3.5.8 Zugriff auf private Daten
Pfeil 3.5.9 Die Trennung von Daten und Code
Pfeil 3.5.10 Namenskonflikte mit »this« lösen
Pfeil 3.5.11 Methode oder Eigenschaft?
Pfeil 3.5.12 Umbenennen von Methoden und Eigenschaften
Pfeil 3.6 Konstruktoren
Pfeil 3.6.1 Konstruktoren bereitstellen
Pfeil 3.6.2 Die Konstruktoraufrufe
Pfeil 3.6.3 Definition von Konstruktoren
Pfeil 3.6.4 »public«- und »internal«-Konstruktoren
Pfeil 3.6.5 »private«-Konstruktoren
Pfeil 3.6.6 Konstruktorenaufrufe umleiten
Pfeil 3.6.7 Vereinfachte Objektinitialisierung
Pfeil 3.7 Der Destruktor
Pfeil 3.8 Konstanten in einer Klasse
Pfeil 3.8.1 Konstanten mit dem Schlüsselwort »const«
Pfeil 3.8.2 Schreibgeschützte Felder mit »readonly«
Pfeil 3.9 Statische Klassenkomponenten
Pfeil 3.9.1 Statische Eigenschaften
Pfeil 3.9.2 Statische Methoden
Pfeil 3.9.3 Statische Klasseninitialisierer
Pfeil 3.9.4 Statische Klassen
Pfeil 3.9.5 Statische Klasse oder Singleton-Pattern?
Pfeil 3.10 Namensräume (Namespaces)
Pfeil 3.10.1 Zugriff auf Namespaces
Pfeil 3.10.2 Die »using«-Direktive
Pfeil 3.10.3 Globaler Namespace
Pfeil 3.10.4 Vermeiden von Mehrdeutigkeiten
Pfeil 3.10.5 Namespaces festlegen
Pfeil 3.10.6 Der »::«-Operator
Pfeil 3.10.7 Unterstützung von Visual Studio 2012 bei den Namespaces
Pfeil 3.11 Stand der Klasse »Circle«

Galileo Computing - Zum Seitenanfang

3.6 KonstruktorenZur nächsten Überschrift

Konstruktoren sind spezielle Methoden, die nur dann aufgerufen werden, wenn mit dem reservierten Wort new eine neue Instanz einer Klasse erzeugt wird. Sie dienen der kontrollierten Initialisierung von Objekten, um beispielsweise Eigenschaften Anfangswerte zuzuweisen, die Verbindung zu einer Datenbank aufzubauen oder eine Datei zu öffnen. Mit Konstruktoren lassen sich unzulässige Objektzustände vermeiden, damit einem Objekt nach Abschluss seiner Instanziierung nicht substanzielle Startwerte fehlen.

Genauso wie Methoden lassen sich Konstruktoren überladen. Allerdings haben Konstruktoren grundsätzlich keinen Rückgabewert, auch nicht void. Bei der Definition eines Konstruktors wird zuerst ein Zugriffsmodifizierer angegeben, direkt dahinter der Klassenbezeichner. Damit sieht der parameterlose Konstruktor der Klasse Circle wie folgt aus:

public Circle() {  } 

Wird ein Objekt mit

Circle kreis = new Circle();

erzeugt, verbergen sich hinter dem Objekterstellungsprozess zwei Schritte:

  • Der erforderliche Speicher für die Daten des Objekts wird reserviert.
  • Ein Konstruktor wird aufgerufen, der das Objekt initialisiert.

Ein Blick in die aktuelle Implementierung der Klasse Circle wirft die Frage auf, wo der Konstruktor zu finden ist, der für die Initialisierung verantwortlich ist. Die Antwort ist einfach: Die augenblickliche Klassenimplementierung enthält zwar explizit keinen Konstruktor, er existiert aber dennoch, allerdings implizit. Diesen impliziten Konstruktor, der parameterlos ist, bezeichnet man auch als Standardkonstruktor.


Galileo Computing - Zum Seitenanfang

3.6.1 Konstruktoren bereitstellenZur nächsten ÜberschriftZur vorigen Überschrift

Um nach der Instanziierung dem Circle-Objekt individuelle Daten zuzuweisen, muss der Benutzer der Klasse jede Eigenschaft einzeln aufrufen, z. B.:

kreis.Radius = 10;
kreis.XCoordinate = 20;
kreis.YCoordinate = 20;

Wäre es nicht sinnvoller, einem Circle-Objekt schon bei dessen Instanziierung den Radius mitzuteilen, vielleicht sogar auch noch gleichzeitig die Bezugspunktkoordinaten? Genau diese Aufgabe können entsprechend parametrisierte Konstruktoren übernehmen.

Das Beispiel der Circle-Klasse wollen wir daher nun so ergänzen, dass bei der Instanziierung unter drei Erstellungsoptionen ausgewählt werden kann:

  • Ein Circle-Objekt kann wie bisher ohne Übergabe von Initialisierungsdaten erzeugt werden.
  • Einem Circle-Objekt kann bei der Instanziierung ein Radius übergeben werden.
  • Bei der Instanziierung kann sowohl der Radius als auch die Lage des Bezugspunktes festgelegt werden.

Mit diesen neuen Forderungen muss der Code der Circle-Klasse wie folgt ergänzt werden:

public Circle() {}

public Circle(int radius) {
Radius = radius;
}

public Circle(int radius, double x, double y) {
XCoordinate = x;
YCoordinate = y;
Radius = radius;
}

Listing 3.36 Konstruktoren in der Klasse »Circle«

Weiter oben haben Sie im Zusammenhang mit der Bereitstellung der Methode Move erfahren, dass die Zuweisung an ein gekapseltes Feld immer über die Eigenschaftsmethode führen sollte. An dieser Stelle wird dieser Sachverhalt bei der Zuweisung des Radius besonders deutlich. Würden Sie den vom ersten Parameter radius beschriebenen Wert direkt dem Feld _Radius zuweisen, könnte das Circle-Objekt tatsächlich einen negativen Radius aufweisen. Die Überprüfung im set-Accessor der Eigenschaftsmethode garantiert aber, dass der Radius des Kreises niemals negativ sein kann.


Galileo Computing - Zum Seitenanfang

3.6.2 Die KonstruktoraufrufeZur nächsten ÜberschriftZur vorigen Überschrift

Im Allgemeinen werden Konstruktoren dazu benutzt, den Feldern eines Objekts bestimmte Startwerte mitzuteilen. Um ein Circle-Objekt zu erzeugen, stehen mit der obigen Konstruktorüberladung drei Möglichkeiten zur Verfügung:

  • Es wird ein Kreis ohne die Übergabe eines Arguments erzeugt. Dabei wird der parameterlose Konstruktor aufgerufen:
    Circle kreis = new Circle();
    Der Kreis hat in diesem Fall den Radius 0, die Bezugspunktkoordinaten werden ebenfalls mit 0 initialisiert.
  • Ein neuer Kreis wird nur mit dem Radius definiert, z. B.:
    Circle kreis = new Circle(10);
    Es wird der Konstruktor aufgerufen, der ein Argument erwartet. Da den Bezugspunktkoordinaten keine Daten zugewiesen werden, sind deren Werte 0.
  • Einem Kreis werden bei der Erzeugung sowohl der Radius als auch die Bezugspunktkoordinaten übergeben.
    Circle kreis = new Circle(10, 15, 20);

Bei der Instanziierung einer Klasse muss der C#-Compiler selbst herausfinden, welcher Konstruktor ausgeführt werden muss. Dazu werden die Typen der übergebenen Argumente mit denen der Konstruktoren verglichen. Liegt eine Doppeldeutigkeit vor oder können die Argumente nicht zugeordnet werden, löst der Compiler einen Fehler aus.


Galileo Computing - Zum Seitenanfang

3.6.3 Definition von KonstruktorenZur nächsten ÜberschriftZur vorigen Überschrift

Trotz der Ähnlichkeit zwischen Konstruktoren und Methoden unterliegen Konstruktoren bestimmten, teilweise auch abweichenden Regeln:

  • Die Bezeichner der Konstruktoren einer Klasse entsprechen dem Klassenbezeichner.
  • Konstruktoren haben grundsätzlich keinen Rückgabewert, auch nicht void.
  • Die Parameterliste eines Konstruktors ist beliebig.
  • Der Konstruktor einer Klasse wird bei der Instanziierung mit dem Schlüsselwort new aufgerufen.
  • Ein Konstruktor kann nicht auf einem bereits bestehenden Objekt aufgerufen werden, beispielsweise um Eigenschaften andere Werte zuzuweisen.

Enthält eine Klasse keinen parametrisierten Konstruktor, wird bei der Erzeugung eines Objekts der implizite, parameterlose Standardkonstruktor aufgerufen. Nun folgt noch eine weitere, sehr wichtige Regel:

Der implizite, parameterlose Standardkonstruktor existiert nur dann, wenn er nicht durch einen parametrisierten Konstruktor überladen wird.

Implementieren Sie nur einen einzigen parametrisierten Konstruktor, enthält die Klasse keinen impliziten Standardkonstruktor mehr. Sie können dann mit

Circle kreis = new Circle();

kein Objekt mehr erzeugen. Wollen Sie das dennoch sicherstellen, muss der parametrisierte Konstruktor ausdrücklich codiert werden. Aus diesem Grund haben wir auch in Circle einen parameterlosen Konstruktor definiert, obwohl er keinen Code enthält. Wir entsprechen damit unserer selbst auferlegten Forderung, ein Circle-Objekt ohne Startwerte erzeugen zu können.


Galileo Computing - Zum Seitenanfang

3.6.4 »public«- und »internal«-KonstruktorenZur nächsten ÜberschriftZur vorigen Überschrift

public deklarierte Konstruktoren stehen allen Benutzern der Klasse zur Verfügung. Das macht natürlich im Grunde genommen nur dann Sinn, wenn die Klasse in einer Klassenbibliothek implementiert wird. In dem Fall kann eine andere Anwendung die öffentlichen Konstruktoren dazu benutzen, ein Objekt nach den Vorgaben zu erzeugen, die in der Parameterliste des Konstruktors festgelegt sind. Manchmal ist es jedoch wünschenswert, einen bestimmten Konstruktor nur in der aktuellen Anwendung offenzulegen (also der Anwendung, in der die Klasse definiert ist), um damit eine bestimmte Instanziierung aus anderen Anwendungen heraus zu unterbinden. Mit dem Zugriffsmodifizierer internal können Sie eine solche Einschränkung realisieren. Denken Sie jedoch daran, dass der implizite Standardkonstruktor grundsätzlich immer öffentlich (public) ist.


Galileo Computing - Zum Seitenanfang

3.6.5 »private«-KonstruktorenZur nächsten ÜberschriftZur vorigen Überschrift

Sie werden immer wieder Klassen entwickeln, die nicht instanziiert werden dürfen. Um die Instanziierung zu verhindern, muss der parameterlose Konstruktor, der standardmäßig public ist, mit einem private-Zugriffsmodifizierer überschrieben werden, z. B.:

public class Demo {
private Demo() {[...]}
[...]
}

Galileo Computing - Zum Seitenanfang

3.6.6 Konstruktorenaufrufe umleitenZur nächsten ÜberschriftZur vorigen Überschrift

Konstruktoren können wie Methoden überladen werden. Jeder Konstruktor enthält dabei typischerweise eine aufgrund der ihm übergebenen Argumente spezifische Implementierung. Manchmal kommt es vor, dass der Konstruktor einer Klasse Programmcode enthält, der von einem zweiten Konstruktor ebenfalls implementiert werden muss. Sehen wir uns dazu die beiden parametrisierten Konstruktoren der Klasse Circle aus Listing 3.36 an:

public Circle(int radius) {
Radius = radius;
}

public Circle(int radius, double x, double y) {
XCoordinate = x;
YCoordinate = y;
Radius = radius;
}

Es fällt auf, dass in beiden Konstruktoren der Radius des Circle-Objekts festgelegt wird. Es liegt nahe, zur Vereinfachung den einfach parametrisierten Konstruktor aus dem dreifach parametrisierten heraus aufzurufen.

Da Konstruktoren eine besondere Spielart der Methoden darstellen und nur über den Operator new aufgerufen werden können, stellt C# eine syntaktische Variante bereit, mit der aus einem Konstruktor heraus ein anderer Konstruktor derselben Klasse aufgerufen wird. Hier kommt erneut das Schlüsselwort this ins Spiel:

public Circle(int radius) {
Radius = radius;
}

public Circle(int radius, double x, double y) : this(radius) {
XCoordinate = x;
YCoordinate = y;
}

Listing 3.37 Konstruktoraufrufumleitung

Die Signatur des dreifach parametrisierten Konstruktors ist um

: this(radius)

ergänzt worden. Dies hat den Aufruf eines anderen Konstruktors, in unserem Fall den Aufruf des einfach parametrisierten, zur Folge. Gleichzeitig wird der vom Aufrufer übergebene Radius, den der dreifach parametrisierte Konstruktor in seiner Parameterliste entgegennimmt, weitergeleitet. Der implizit aufgerufene einfach parametrisierte Konstruktor wird ausgeführt und gibt die Kontrolle danach an den aufrufenden Konstruktor zurück.

Konstruktorverkettung – die bessere Lösung

Betrachten wir unsere drei Konstruktoren in Circle jetzt einmal aus der Distanz und nehmen wir an, wir würden den dreifach parametrisierten aufrufen. Dieser leitet in den zweifach parametrisierten um und dieser wiederum an den parameterlosen. Solche Verkettungen über mehrere Konstruktoren hinweg können natürlich noch extremer ausfallen, wenn noch mehr Konstruktoren in der Klasse eine Rolle spielen. Nicht nur, dass die vielen zwischengeschalteten Aufrufe eine Leistungseinbuße nach sich ziehen, auch die Verteilung der Programmlogik in viele Fragmente trägt nicht dazu bei, den Code überschaubar zu halten.

Aus den genannten Gründen sollten Sie ein anderes Verkettungsprinzip bevorzugen: Leiten Sie immer direkt zu dem Konstruktor mit den meisten Parametern um. Dieser muss dann die gesamte Initialisierungslogik enthalten. Soweit möglich, werden die Übergabeargumente des aufgerufenen Konstruktors weitergeleitet, ansonsten geben Sie Standardwerte an.

Mit dieser Überlegung ändern sich die Konstruktoren in Circle wie folgt:

public Circle() : this(0, 0, 0) {}

public Circle(int radius) : this(radius, 0, 0) {}

public Circle(int radius, double x, double y)
{
Radius = radius;
XCoordinate = x;
YCoordinate = y;
}

Listing 3.38 Überarbeitete Konstruktoren in der Klasse »Circle«


Galileo Computing - Zum Seitenanfang

3.6.7 Vereinfachte ObjektinitialisierungZur vorigen Überschrift

Um einem Circle-Objekt mit dem dreifach parametrisierten Konstruktor Daten zuzuweisen, schreiben Sie den folgenden Code:

Circle kreis = new Circle(12, -100, 250);

Es geht aber auch anders. Sie können die Startwerte in derselben Anweisungszeile in geschweiften Klammern angeben, wie das folgende Beispiel zeigt:

Circle kreis = new Circle() { XCoordinate = -7, YCoordinate = 2,Radius = 2 };

Sie können mit dieser Notation sogar auf die runden Klammern verzichten. Diese Art der Objektinitialisierung wird als vereinfachte Objektinitialisierung bezeichnet und orientiert sich nicht an etwaig vorhandenen Konstruktoren. Mit anderen Worten bedeutet dies, dass Sie diese Objektinitialisierung auch dann benutzen können, wenn eine Klasse nur den parameterlosen Standardkonstruktor aufweist.

Sie müssen nicht zwangsläufig alle Eigenschaften angeben. Felder, denen kein spezifischer Wert übergeben wird, werden mit dem typspezifischen Standardwert initialisiert. Die Reihenfolge der durch ein Komma angeführten Eigenschaften spielt keine Rolle, z. B.:

Circle kreis = new Circle {XCoordinate = -100,YCoordinate = -100,Radius = 12};

Die IntelliSense-Hilfe unterstützt Sie bei dieser Initialisierung und zeigt Ihnen die Eigenschaften an, die noch nicht initialisiert sind. Übergeben Sie sowohl im Konstruktoraufruf als auch in den geschweiften Klammern derselben Eigenschaft einen Wert, wird der Wert des Konstruktors verworfen. Das ist wichtig zu wissen, denn ein mit

Circle kreis = new Circle(50) { Radius = 678 };

erzeugtes Objekt hat den Radius 678.

Es hat den Anschein, dass die vereinfachte Objektinitialisierung die Bereitstellung von überladenen Konstruktoren überflüssig macht. Dem ist nicht so, und Sie sollten eine solche Idee auch schnell wieder verwerfen. Konstruktoren folgen der Philosophie der Objektorientierung und werden von jeder .NET-Sprache unterstützt. Das ist bei der vereinfachten Objektinitialisierung nicht der Fall, die im Zusammenhang mit LINQ (Language Integrated Query, siehe Kapitel 11) eingeführt worden ist und nicht die überladenen Konstruktoren ersetzen soll.



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