01.11.2013 Aufrufe

C# Objektorientierte Programmierung - Tutorials.de

C# Objektorientierte Programmierung - Tutorials.de

C# Objektorientierte Programmierung - Tutorials.de

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

<strong>C#</strong><br />

<strong>Objektorientierte</strong><br />

<strong>Programmierung</strong><br />

1. Vorwort<br />

2. Einleitung<br />

3. Entwicklungsumgebung<br />

4. Grundlagen<br />

5. Debugging<br />

6. Objektorientierung<br />

(Ver. 1.03)<br />

7. Fehlerbehandlung<br />

by Erik Bartmann<br />

1


1 <strong>Objektorientierte</strong> <strong>Programmierung</strong> ..............................................................4<br />

Grundlagen.......................................................................................................4<br />

Klassen und Objekte ........................................................................................5<br />

Klassen<strong>de</strong>finition .............................................................................................5<br />

Instanzvariablen ...............................................................................................7<br />

Objektgenerierung............................................................................................8<br />

Mehrere Objekte generieren.......................................................................12<br />

Unterschie<strong>de</strong> bei <strong>de</strong>r Zuweisung................................................................16<br />

Metho<strong>de</strong>n .......................................................................................................20<br />

Zugriffsmodifizierer...................................................................................25<br />

Wertübergabe.............................................................................................26<br />

Call by value ..............................................................................................31<br />

Call by reference........................................................................................33<br />

Wertrückgabe.............................................................................................34<br />

Wissenswertes über return .........................................................................36<br />

Metho<strong>de</strong>nüberladung .................................................................................38<br />

Beliebig viele Argumente ..........................................................................41<br />

Konstruktoren (spezialisierte Metho<strong>de</strong>n).......................................................44<br />

Konstruktorüberladung ..............................................................................48<br />

Standardkonstruktor...................................................................................49<br />

Konstruktor ruft Konstruktor .....................................................................50<br />

this..................................................................................................................52<br />

Garbage Collection ........................................................................................53<br />

2


Destruktoren ..................................................................................................55<br />

Eigenschaften.................................................................................................58<br />

Konstanten .....................................................................................................62<br />

Vererbung ......................................................................................................63<br />

Grundlagen ................................................................................................63<br />

Ableiten von einer Basisklasse ..................................................................64<br />

Kindklasse ruft Basisklasse .......................................................................69<br />

Konstruktoren im Kontext <strong>de</strong>r Vererbung .................................................71<br />

Welcher Konstruktor wird wann aufgerufen?............................................71<br />

Member ver<strong>de</strong>cken ....................................................................................73<br />

Polymorphie...............................................................................................76<br />

Statische Klassen ...........................................................................................82<br />

Konstruktoren ............................................................................................85<br />

Globale Variablen......................................................................................89<br />

Main-Parameter .........................................................................................92<br />

Enumerationen...............................................................................................96<br />

Elemente <strong>de</strong>r Enumeration ausgeben.......................................................100<br />

Werte <strong>de</strong>r Konstanten ausgeben ..............................................................102<br />

Konstantennamen ausgeben.....................................................................103<br />

Basisdatentyp zur Laufzeit ermitteln .......................................................105<br />

3


1 <strong>Objektorientierte</strong> <strong>Programmierung</strong><br />

Grundlagen<br />

Das folgen<strong>de</strong> Kapitel befasst sich mit <strong>de</strong>r <strong>Objektorientierte</strong>n <strong>Programmierung</strong> -<br />

kurz OOP genannt - unter <strong>C#</strong>. Was sich so leicht dahinsagt, bereitet manchen<br />

am Anfang möglicherweise Kopfschmerzen. Doch lassen Sie sich durch diese<br />

Aussage nicht entmutigen, <strong>de</strong>nn wir wer<strong>de</strong>n auf unterster Ebene beginnen.<br />

Gera<strong>de</strong> für Entwickler, die aus <strong>de</strong>r Ecke <strong>de</strong>r prozeduralen <strong>Programmierung</strong><br />

(z.B. C o<strong>de</strong>r Basic) kommen, ist diese neue Denkweise möglicherweise etwas<br />

ungewohnt. Die Entwickler von objektorientierten Sprachen wie z.B. <strong>C#</strong>, C++,<br />

VB.NET, Java, Delphi, um nur einige zu nennen, waren bestrebt, die Realität so<br />

naturgetreu wie möglich abzubil<strong>de</strong>n. Alles, was wir so um uns herum sehen,<br />

kann angefasst und auf allgemeiner Ebene als Objekt angesehen wer<strong>de</strong>n. Da<br />

haben wir auch schon <strong>de</strong>n Begriff, von <strong>de</strong>r die o.g. Sprachen ihren Zusatz<br />

haben. Betrachten wir in unserem Fall nur Objekte, die von Menschenhand<br />

gefertigt wur<strong>de</strong>n o<strong>de</strong>r noch wer<strong>de</strong>n. Mein folgen<strong>de</strong>s Beispiel liegt zwar etwas in<br />

<strong>de</strong>r Zukunft, doch die ist ja Dank StarTrek in greifbare Nähe gerückt. Die<br />

Konstrukteure eines fiktiven Raumschiffs haben sich natürlich vor <strong>de</strong>m Bau<br />

Gedanken über Aussehen, Größe, Spezifikationen bzw. Bewaffnung gemacht.<br />

Sie haben nicht einfach drauf los gebaut, um zu sehen, (ob) was daraus wird,<br />

son<strong>de</strong>rn einen Konstruktionsplan erstellt, in <strong>de</strong>m alle Details über die spätere<br />

Realisierung <strong>de</strong>s Projektes enthalten sind. Mit dieser Vorlage kann ein einzelnes<br />

o<strong>de</strong>r auch eine ganze Flotte von Raumschiffen geschaffen wer<strong>de</strong>n. Übertragen<br />

wir diese Vorlage auf die <strong>Objektorientierte</strong> <strong>Programmierung</strong>, so sprechen wir<br />

von einer Klasse. Diese Klasse dient als Schablone für zukünftig zu<br />

realisieren<strong>de</strong> Objekte und enthält Anweisungen wie diese aufzubauen sind. Da<br />

haben wir auch schon die bei<strong>de</strong>n ersten wichtigen Schlagwörter <strong>de</strong>r OOP.<br />

Klasse und Objekt. Sie erkennen vielleicht jetzt schon, dass es sich hierbei um<br />

4


eine Vorgehensweise han<strong>de</strong>lt, die versucht ist, die Realität möglichst<br />

naturgetreu abzubil<strong>de</strong>n.<br />

Klassen und Objekte<br />

Eine Klasse ist ein Bauplan bzw. eine Vorlage, die beschreibt, wie ein Objekt<br />

zu realisieren ist. Objekte wer<strong>de</strong>n auch als Klasseninstanzen bezeichnet.<br />

In <strong>de</strong>r OOP nennt man <strong>de</strong>n Übergang von <strong>de</strong>r Klasse zum Objekt<br />

Instanziierung.<br />

Klassen<strong>de</strong>finition<br />

Eine Klassen<strong>de</strong>finition wird immer mit <strong>de</strong>m Schlüsselwort class eingeleitet,<br />

wobei <strong>de</strong>r darauf folgen<strong>de</strong> Klassenname mit einem Großbuchstaben beginnen<br />

sollte. Wie<strong>de</strong>r eine Konvention, an die Sie sich halten sollten, aber nicht<br />

müssen.<br />

5


Folgen<strong>de</strong> drei Bereiche gibt es bei <strong>de</strong>r allgemeinen Klassen<strong>de</strong>finition<br />

1. Vergabe <strong>de</strong>s Klassenname<br />

2. Deklaration <strong>de</strong>r Instanzvariablen<br />

3. Deklaration <strong>de</strong>r Metho<strong>de</strong>n<br />

Wir halten fest, dass ein Objekt die Bün<strong>de</strong>lung von Daten (Instanzvariablen)<br />

und <strong>de</strong>n entsprechen<strong>de</strong>n Funktionen (Metho<strong>de</strong>n) zur Bearbeitung dieser<br />

Daten ist.<br />

6


Instanzvariablen<br />

Schauen wir uns einmal das Raumschiff als Objekt genauer an. Wie können wir<br />

es beschreiben, bzw. welche statischen Attribute, auch Eigenschaften genannt,<br />

weist das Objekts auf?<br />

♦ Länge<br />

♦ Breite<br />

♦ Farbe<br />

♦ Bautyp<br />

♦ Geschwindigkeit<br />

♦ Höchstgeschwindigkeit<br />

♦ Anzahl <strong>de</strong>r Besatzung<br />

♦ Waffen<br />

Das sind nur ein paar Beispiel-Eigenschaften und wir wollen es hierbei<br />

bewen<strong>de</strong>n lassen. Unser Raumschiff hat z.B. eine Länge von 200 Metern, eine<br />

Breite von 100 Metern. Die Farbe ist silber-grau und seine momentane<br />

Geschwindigkeit beträgt Warp 2. Es ist mit einer 200 Mann starken Besatzung<br />

unterwegs. Diese Eigenschaften müssen irgendwie gespeichert wer<strong>de</strong>n und was<br />

liegt näher, als Variablen dafür zu verwen<strong>de</strong>n. Jedoch wer<strong>de</strong>n die Variablen im<br />

Kontext <strong>de</strong>r OOP, Instanzvariablen o<strong>de</strong>r Fel<strong>de</strong>r genannt. Die allgemeine<br />

Syntax zur Deklaration von Instanzvariablen lautet:<br />

Zugriffstyp Datentyp Variablenname;<br />

Bis auf <strong>de</strong>n Zugriffstyp public ähnelt die Deklaration <strong>de</strong>r, einer lokalen<br />

Variablen. Schauen wir uns einmal folgen<strong>de</strong> Klassen<strong>de</strong>finition an:<br />

7


Dotty: „Was be<strong>de</strong>utet <strong>de</strong>nn das Schlüsselwort public?“<br />

Es ist ein Zugriffsmodifizierer, <strong>de</strong>r festlegt, wie auf das entsprechen<strong>de</strong> Element<br />

zugegriffen wer<strong>de</strong>n darf. Die genauere Be<strong>de</strong>utung kommt ein wenig später. Wir<br />

können es an dieser Stelle erst einmal ignorieren.<br />

Objektgenerierung<br />

Dotty: „Nach<strong>de</strong>m wir jetzt eine Klasse <strong>de</strong>finiert haben, stellt sich mir Frage,<br />

was wir mit <strong>de</strong>r Klasse machen und wie wir sie nutzen können?“<br />

Durch eine Klassen<strong>de</strong>finition wird quasi ein neuer Datentyp erzeugt. Die<br />

Deklaration einer Variablen bereitet nach <strong>de</strong>m Studium <strong>de</strong>r Grundlagen<br />

hoffentlich keine Probleme mehr. Sie erfolgt nach <strong>de</strong>m Schema:<br />

Datentyp Variablenname;<br />

Mit <strong>de</strong>r Anweisung<br />

Raumschiff meinSpee<strong>de</strong>r;<br />

wird jedoch in <strong>C#</strong> noch kein konkretes Objekt erzeugt. Es existiert lediglich die<br />

Objektvariable meinSpee<strong>de</strong>r, die später als eine Art Zeiger, auch Referenz<br />

genannt, auf die Startadresse eines bestimmten Speicherbereich (Heap)<br />

verweist. Im Moment besitzt sie jedoch <strong>de</strong>n Wert null und ist lediglich<br />

8


vorbereitet wor<strong>de</strong>n, auf ein Objekt zu zeigen. Wie schon eingangs erwähnt,<br />

existieren im CTS (Common Type System) von .NET zwei unterschiedliche<br />

Kategorien von Datentypen.<br />

♦ Wertetypen<br />

♦ Verweis- bzw. Referenztypen<br />

Wertetypen speichern ihren Wert direkt und wer<strong>de</strong>n im Stack abgelegt, wogegen<br />

Verweisvariablen eine Referenz auf einen Speicherbereich, <strong>de</strong>m Heap, besitzen,<br />

in <strong>de</strong>m die eigentlichen Daten gespeichert sind.<br />

Abb. 1:<br />

new<br />

Wertetypen und Referenztypen<br />

Um ein reales Objekt aus objektorientierter Sicht zu bekommen, wird das<br />

Schlüsselwort new verwen<strong>de</strong>t. Erst danach wird ein Speicherbereich im Heap<br />

bereitgestellt. Die folgen<strong>de</strong> Anweisung generiert das Objekt mit Hilfe <strong>de</strong>r<br />

Klassen<strong>de</strong>finition:<br />

9


meinSpee<strong>de</strong>r = new Raumschiff();<br />

Schauen wir uns das komplette Programm an und versetzten es über einen<br />

Haltepunkt nach <strong>de</strong>m Start mit <strong>de</strong>r F5 - Taste in <strong>de</strong>n Debug-Modus. Stören Sie<br />

sich im folgen<strong>de</strong>n Beispiel nicht an <strong>de</strong>n Schlangenlinien unterhalb <strong>de</strong>r<br />

Instanzvariablen. Sie besagen nur, dass sie im Moment noch keinen Wert<br />

zugewiesen bekommen haben und <strong>de</strong>shalb einen Standartwert besitzen. Welche<br />

das sind, erfahren Sie über das Fenster Lokal nach erreichen <strong>de</strong>s Debug-Modus.<br />

Zeile<br />

Erklärung<br />

10 - 17 Klassen<strong>de</strong>finition <strong>de</strong>r Klasse Raumschiff. In ihr wer<strong>de</strong>n Instanzvariablen <strong>de</strong>klariert, die<br />

10


zur Aufnahme von Objekteigenschaften dienen.<br />

24 Deklaration <strong>de</strong>r Objektvariablen meinSpee<strong>de</strong>r mittels <strong>de</strong>r Klassen<strong>de</strong>finition<br />

Raumschiff. (Es wur<strong>de</strong> noch kein Objekt erzeugt!)<br />

26 Instanziierung <strong>de</strong>s Objektes meinSpee<strong>de</strong>r mit Hilfe <strong>de</strong>s Schlüsselwortes new. Erst jetzt<br />

existiert ein reales Objekt im Heap.<br />

Tab. 1: Co<strong>de</strong>-Erläuterungen<br />

Starten Sie die Anwendung, wird die Ausführung in Zeile 27 über <strong>de</strong>n gesetzten<br />

Haltepunkt unterbrochen. Ein Blick in Fenster Lokal, gibt Aufschluss über die<br />

zu diesem Zeitpunkt initialisierten Variablen.<br />

Abb. 2:<br />

Fenster Lokal im Debug-Modus<br />

Wir erkennen, dass es eine Variable mit Namen meinSpee<strong>de</strong>r vom Datentyp<br />

ConsoleApplication16.Raumschiff gibt. Der Name ConsoleApplication16 gibt<br />

in unserem Fall <strong>de</strong>n Namespace an. Die angezeigten Werte entsprechen <strong>de</strong>n<br />

Defaultzuweisungen, welche implizit vorgenommen wer<strong>de</strong>n.<br />

Icon<br />

Erklärung<br />

Signalisiert, dass es sich um eine Variable han<strong>de</strong>lt<br />

Tab. 2: Iconerklärung<br />

11


Deklaration und Instanziierung können in einer einzigen Anweisungszeile<br />

zusammengefasst wer<strong>de</strong>n.<br />

Zugriff auf Eigenschaften<br />

Da wir über die Klassen<strong>de</strong>finition einen neuen Datentyp geschaffen haben, stellt<br />

sich uns die Frage, wie man nach <strong>de</strong>r Objektgenerierung auf die Eigenschaften<br />

zugreifen kann. Der Punktoperator . wur<strong>de</strong> von uns schon mehrfach verwen<strong>de</strong>t,<br />

um eine Verbindung zwischen Objekt und Member herzustellen. (z.B.<br />

Console.ReadLine()) Der Zugriff erfolgt mit <strong>de</strong>r Syntax:<br />

Objekt.Member<br />

Soll unser Raumschiff meinSpee<strong>de</strong>r mit 200 Mann Besatzung auf die Reise<br />

gehen, dann lautet die Anweisung:<br />

meinSpee<strong>de</strong>r.intBesatzung = 200;<br />

Mehrere Objekte generieren<br />

Der Grund einer Klasse bzw. Vorlage ist natürlich die Wie<strong>de</strong>rverwendbarkeit.<br />

Was nützt mir ein einziges Raumschiff, wenn ich mich gegen einen mächtigen<br />

Gegner behaupten muss? Gar nichts! Aus diesem Grund muss ich mehrere<br />

Kopien anhand <strong>de</strong>r Vorlage anfertigen.<br />

12


Die folgen<strong>de</strong> Anwendung nutzt die gleiche Klassen<strong>de</strong>finition, instanziiert<br />

jedoch 2 zwei Objekte:<br />

13


Die bei<strong>de</strong>n Objekte meinSpee<strong>de</strong>r bzw. <strong>de</strong>inSpee<strong>de</strong>r besitzen <strong>de</strong>n gleichen<br />

Ursprung: die Klassen<strong>de</strong>finition Raumschiff. Sie wer<strong>de</strong>n jeweils in <strong>de</strong>n Zeilen<br />

26 und 27 instanziiert. Es sind aber eigenständige Objekte, die sonst keine<br />

Gemeinsamkeiten besitzen. Je<strong>de</strong>s von Ihnen hat eigene Eigenschaften bzw.<br />

Attribute (Länge, Breite, Farbe und Besatzung). Ein Blick in das Fenster Lokal<br />

gibt Aufschluss über die bei<strong>de</strong>n unabhängigen Objekte.<br />

14


Abb. 3:<br />

Fenster Lokal im Debug-Modus<br />

Hier ein Tipp, <strong>de</strong>r das Arbeiten bzw. erkennen von Objekt-Membern extrem<br />

erleichtert. Wie<strong>de</strong>r leistet IntelliSense unschätzbare Dienste.<br />

Wenn Sie die Eigenschaften eines Objektes initialisieren wollen, geben Sie <strong>de</strong>n<br />

Namen <strong>de</strong>r Objektvariablen, gefolgt vom Punktoperator . ein. Augenblicklich<br />

mel<strong>de</strong>t sich IntelliSense und bietet die Member zur Auswahl an, welche mit<br />

<strong>de</strong>m Objekt verknüpft sind. Sie erkennen aufgrund <strong>de</strong>r optischen<br />

15


Differenzierung (unterschiedliche Icons) sofort die Instanzvariablen wie<strong>de</strong>r. Es<br />

gibt aber eine Bedingung, auf die wir noch zu sprechen kommen: „Es wer<strong>de</strong>n<br />

hier nur Instanzvariablen zur Auswahl angeboten, die <strong>de</strong>n Zugriffsmodifizierer<br />

public haben.“<br />

Unterschie<strong>de</strong> bei <strong>de</strong>r Zuweisung<br />

Kommen wir zu einem gravieren<strong>de</strong>n Unterschied bei <strong>de</strong>r Zuweisung zwischen<br />

Wertetypen und Referenztypen. Das folgen<strong>de</strong> Beispiel zeigt eine<br />

Wertzuweisung, bei <strong>de</strong>m <strong>de</strong>r Wert <strong>de</strong>r Variablen auf <strong>de</strong>r rechten Seite in die<br />

Variable auf <strong>de</strong>r linken Seite kopiert wird. Es existieren zwei unabhängige<br />

Variablen.<br />

Die Konsolen-Ausgabe lautet:<br />

Wert1: 10<br />

Wert2: 42<br />

16


Zeile<br />

Erklärung<br />

14 Die Variable intWert1 wird <strong>de</strong>klariert und mit <strong>de</strong>m Wert 10 initialisiert<br />

15 Die Variable intWert2 wird <strong>de</strong>klariert und mit einer Kopie <strong>de</strong>s Wertes von<br />

intWert1 initialisiert.<br />

16 Der Variablen intWert2 wird <strong>de</strong>r Wert 42 zugewiesen, was aber keine<br />

Auswirkung auf <strong>de</strong>n Inhalt von intWert1 hat.<br />

Tab. 3: Co<strong>de</strong>-Erläuterungen<br />

Das folgen<strong>de</strong> Beispiel zeigt Ihnen die Zuweisung bei Referenztypen. Sie erfolgt<br />

in einer Weise, die Sie vielleicht nicht vermutet haben.<br />

17


Die Konsolen-Ausgabe lautet:<br />

99<br />

18


Bis zur Zeile 39 besitzen wir zwei eigenständige Raumschiffe (meinSpee<strong>de</strong>r,<br />

<strong>de</strong>inSpee<strong>de</strong>r), die über je eine Objektreferenz anzusprechen sind. Je<strong>de</strong>s von<br />

ihnen besitzt individuelle Eigenschaften, was <strong>de</strong>r Zustand „vorher“<br />

wi<strong>de</strong>rspiegelt. In Zeile 42 erfolgt nun durch meinSpee<strong>de</strong>r =<br />

<strong>de</strong>inSpee<strong>de</strong>r nicht etwa ein Kopieren <strong>de</strong>s Objektes <strong>de</strong>inSpee<strong>de</strong>r nach<br />

meinSpee<strong>de</strong>r, son<strong>de</strong>rn ein Kopieren <strong>de</strong>r Referenz. Es existieren ab dieser Zeile<br />

zwei Objektreferenzen, die auf ein und dasselbe Objekt verweisen, was <strong>de</strong>r<br />

Zustand „nachher“ wi<strong>de</strong>rspiegelt. Sollten Sie jetzt versucht sein, über die<br />

Objektreferenz meinSpee<strong>de</strong>r das Objekt zu manipulieren (Zeile 43), kann<br />

natürlich über die an<strong>de</strong>re Referenz <strong>de</strong>inSpee<strong>de</strong>r das Ergebnis abgefragt wer<strong>de</strong>n<br />

(Zeile 44). Egal welchen Zugang zum Objekt Sie wählen, Sie sprechen nur ein<br />

Objekt an.<br />

Dotty: „Wie kommen wir jetzt wie<strong>de</strong>r an das alte Raumschiff meinSpee<strong>de</strong>r<br />

heran?“<br />

19


Das ist das Problem. Gar nicht mehr. Verliert ein Objekt seine letzte Referenz,<br />

ist es nicht mehr ansprechbar und wird durch eine Einrichtung, die Garbage<br />

Collection genannt wird, entsorgt. Es ist die interne .NET Müllabfuhr, die alle<br />

herrenlosen Objekte aufspürt und <strong>de</strong>n zuvor belegten Speicherplatz wie<strong>de</strong>r<br />

freigibt. Das hat natürlich enorme Vorteile, <strong>de</strong>nn Sie brauchen sich nicht weiter<br />

um diese Angelegenheit wie z.B. in <strong>de</strong>r Programmiersprache C++ zu kümmern.<br />

Wird dort <strong>de</strong>r Aufräumprozess vergessen, kommt es zu so genannten<br />

Speicherlecks, die unter Umstän<strong>de</strong>n zur Laufzeit eines Programms <strong>de</strong>n<br />

kostbaren freien Speicher nach und nach aufbrauchen. Weitere Details erfahren<br />

Sie im Kapitel über die Garbage Collection.<br />

Metho<strong>de</strong>n<br />

Wie Sie in <strong>de</strong>r Klassen<strong>de</strong>finition gesehen haben, gibt es neben <strong>de</strong>n<br />

Instanzvariablen noch einen weiteren elementaren Bestandteil einer Klasse. Es<br />

sind die Metho<strong>de</strong>n. Sie sind Unterprogramme, die eine o<strong>de</strong>r mehrere<br />

Anweisungen enthalten können. Von außen betrachtet kann sie als eine einzelne<br />

Anweisung angesehen wer<strong>de</strong>n, die über ihren Metho<strong>de</strong>nnamen aufgerufen wird.<br />

Eine äußerst wichtige haben Sie schon im Kapitel über die Grundlagen kennen<br />

gelernt. Es ist die Metho<strong>de</strong> Main. Die allgemeine Syntax lautet:<br />

Zugriffstyp Rückgabetyp Metho<strong>de</strong>nname(Parameterliste)<br />

{<br />

// Metho<strong>de</strong>nrumpf<br />

// Anweisung(en)<br />

}<br />

Was be<strong>de</strong>uten die einzelnen Elemente bei <strong>de</strong>r<br />

Definition einer Metho<strong>de</strong>?<br />

Element<br />

Zugriffstyp<br />

Erklärung<br />

Der Zugriff wird über einen so genannten Zugriffsmodifizierer gesteuert<br />

20


und legt fest, wer die Metho<strong>de</strong> im aktuellen Kontext aufrufen darf.<br />

Nähere Informationen liefert <strong>de</strong>r Abschnitt über Zugriffsmodifizierer.<br />

Rückgabetyp Der Rückgabetyp legt fest, welchen Datentyp die Metho<strong>de</strong><br />

zurückliefert. Wird kein Wert zurückgeliefert, muss <strong>de</strong>r Typ auf void<br />

gesetzt wer<strong>de</strong>n.<br />

Metho<strong>de</strong>nname<br />

Parameterliste<br />

Der Name, mit <strong>de</strong>m die Metho<strong>de</strong> aufgerufen wird. Er kann frei gewählt<br />

wer<strong>de</strong>n, darf jedoch kein Schlüsselwort sein.<br />

Die Parameterliste befin<strong>de</strong>t sich innerhalb <strong>de</strong>s run<strong>de</strong>n Klammernpaares<br />

(...) nach <strong>de</strong>m Metho<strong>de</strong>nnamen und beinhaltet die<br />

Datentypbezeichnungen und Variablennamen, die zur Aufnahme <strong>de</strong>r<br />

übergebenen Argumente dienen. Mehrere Parameter wer<strong>de</strong>n durch<br />

Kommata voneinan<strong>de</strong>r getrennt angegeben. Wer<strong>de</strong>n keine Argumente<br />

übergeben, ist die Parameterliste leer, wobei die run<strong>de</strong>n Klammern<br />

nicht entfallen dürfen.<br />

Metho<strong>de</strong>nrumpf Der Metho<strong>de</strong>nrumpf wird durch das geschweifte Klammernpaar {...}<br />

festgelegt und enthält die Anweisung(en), die die Funktionsweise <strong>de</strong>r<br />

Metho<strong>de</strong> ausmachen.<br />

Tab. 4: Metho<strong>de</strong>n-Elemente<br />

Mit Hilfe <strong>de</strong>r Metho<strong>de</strong>n kann auf die Daten einer Klasse zugegriffen wer<strong>de</strong>n,<br />

um sie zu lesen o<strong>de</strong>r auch zu modifizieren.<br />

Dotty: „Stop, stop, dass ist meines Wissens nicht ganz korrekt. Der Zugriff<br />

auf Eigenschaften erfolgte im letzten Beispiel ohne eine Metho<strong>de</strong>. Es wur<strong>de</strong><br />

einfach die Objektvariable und <strong>de</strong>ssen Eigenschaft angegeben.“<br />

Dem muss ich zustimmen, doch das ist nicht die Regel und diente nur als<br />

anfängliches Beispiel. Ich komme jetzt zu einem weiteren wichtigen Eckpfeiler<br />

<strong>de</strong>r OOP. Es ist die Kapselung. Der Zugriff auf die Eigenschaften eines<br />

Objekts, die in Instanzvariablen abgelegt wer<strong>de</strong>n, erfolgte bisher direkt. Durch<br />

die Anweisung<br />

21


meinSpee<strong>de</strong>r.intBesatzung = 200;<br />

war es möglich, die Eigenschaft <strong>de</strong>s Objektes unmittelbar zu manipulieren. Die<br />

folgen<strong>de</strong> Grafik veranschaulicht <strong>de</strong>n Sachverhalt.<br />

Abb. 4:<br />

Direkter Zugriff auf die Daten eines Objekts<br />

Das war jedoch nur möglich, weil <strong>de</strong>r Zugriffsmodifizierer <strong>de</strong>r betreffen<strong>de</strong>n<br />

Eigenschaft auf public (öffentlich) steht. Ein Zugriff von außen auf die Daten<br />

<strong>de</strong>s Objekts ist somit erlaubt. Stellen Sie sich vor, Sie sind Captain dieses<br />

Raumschiffs und stellen auf einmal fest, dass sich an Bord mehr<br />

Besatzungsmitglie<strong>de</strong>r befin<strong>de</strong>n, als es zur Erfüllung Ihres Auftrages notwendig<br />

ist. Aufgrund <strong>de</strong>s begrenzten Platzangebotes kommt es nach kurzer Zeit zu<br />

Streitigkeiten untereinan<strong>de</strong>r, was die gesamte Mission gefähr<strong>de</strong>t.<br />

22


Was ist genau passiert? Durch die Anweisung<br />

meinSpee<strong>de</strong>r.intBesatzung = 750;<br />

ist die maximal zulässige Besatzungsstärke von 200 Mann um mehr als das 3-<br />

fache überschritten wor<strong>de</strong>n. Niemand hat sich verantwortlich gefühlt eine<br />

Zugangskontrolle einzurichten, um ein <strong>de</strong>rartiges Problem erst gar nicht<br />

entstehen zu lassen.<br />

Dotty: „Was können wir aber unternehmen, damit es nicht dazu kommt?“<br />

Wir müssen zwei Modifikationen vornehmen:<br />

1. Den öffentlichen Zugriff von außen unterbin<strong>de</strong>n<br />

2. Den Zugang über eine Kontrollinstanz überwachen lassen, so dass<br />

eingeschritten wer<strong>de</strong>n kann, wenn die maximale o<strong>de</strong>r auch minimale<br />

Besatzungsanzahl über- bzw. unterschritten wird.<br />

Das be<strong>de</strong>utet im Detail, dass in Schritt 1 in <strong>de</strong>r Deklarationszeile <strong>de</strong>r<br />

Instanzvariablen <strong>de</strong>r Zugriffsmodifizierer public (öffentlich) durch private<br />

(privat) ersetzt wer<strong>de</strong>n muss. Durch diese Modifikation kann auf die<br />

Instanzvariable nur noch innerhalb <strong>de</strong>r Klasse zugegriffen wer<strong>de</strong>n. Da die<br />

Vorgehensweise für alle bis jetzt genannten Instanzvariablen gleich ist,<br />

konzentrieren wir uns im nun folgen<strong>de</strong>n Beispiel auf intBesatzung.<br />

23


private int intBesatzung;<br />

Versuchen wir jetzt wie bisher auf die Eigenschaft durch<br />

meinSpee<strong>de</strong>r.intBesatzung = 750;<br />

zuzugreifen, erhalten wir eine Fehlermeldung:<br />

Das ist genau das, was beabsichtigt war. Jetzt kommt Schritt 2. Der Zugriff auf<br />

die Daten ist nur über eine öffentliche Metho<strong>de</strong> gestattet:<br />

Abb. 5:<br />

Indirekter Zugriff auf die Daten eines Objektes<br />

Sie sehen, dass zwischen <strong>de</strong>m (öffentlichen) Zugriff und <strong>de</strong>n (privaten) Daten<br />

ein Element eingefügt wur<strong>de</strong>. Die Metho<strong>de</strong>. Sie übernimmt bei entsprechen<strong>de</strong>r<br />

Kodierung die Überwachung <strong>de</strong>s Zugangs zum Raumschiff und stellt das<br />

Bin<strong>de</strong>glied zwischen <strong>de</strong>n privaten, gekapselten Instanzvariablen und <strong>de</strong>r<br />

Außenwelt dar. Das ist genau die Strategie, die die OOP verfolgt. Die<br />

24


Manipulation <strong>de</strong>r von außen unsichtbaren Eigenschaften ist nur über öffentliche<br />

Metho<strong>de</strong>n zulässig bzw. gewünscht.<br />

Da wir an <strong>de</strong>m Punkt gelangt sind, wo Sie über Eigenschaften und Metho<strong>de</strong>n<br />

bescheid wissen, erkennen Sie, dass in <strong>de</strong>r OOP die Daten (Instanzvariablen)<br />

und die Funktionen (Metho<strong>de</strong>n) zur Manipulation <strong>de</strong>rselben, eine Einheit<br />

(Objekt) bil<strong>de</strong>n.<br />

Zugriffsmodifizierer<br />

Jetzt wird es Zeit, ein paar Worte über die schon mehrfach verwen<strong>de</strong>ten<br />

Zugriffsmodifizierer public bzw. private zu verlieren. Sie legen die Sichtbarkeit<br />

bzw. Zugriffsmöglichkeit <strong>de</strong>r Klassenelemente, auch Member genannt, fest.<br />

Zugriffsmodifizierer<br />

public<br />

private<br />

protected<br />

Be<strong>de</strong>utung<br />

Auf Klassenelemente, die als public <strong>de</strong>klariert wur<strong>de</strong>n, kann über<br />

eine Referenz auf die Klasse zugegriffen wer<strong>de</strong>n.<br />

Auf Klassenelemente, die als private <strong>de</strong>klariert wur<strong>de</strong>n, kann nur von<br />

innerhalb <strong>de</strong>r Klasse zugegriffen wer<strong>de</strong>n. In abgeleiteten Klassen<br />

kann auf diese Elemente nicht zugegriffen wer<strong>de</strong>n.<br />

Gleiches Verhalten, wie mit private. Jedoch kann in abgeleiteten<br />

Klassen auf diese Elemente zugegriffen wer<strong>de</strong>n.<br />

25


Tab. 5: Zugriffsmodifizierer für Klassenelemente<br />

Wird kein Zugriffsmodifizierer angegeben, wird er implizit auf private<br />

gesetzt.<br />

Wertübergabe<br />

Schauen Sie sich die folgen<strong>de</strong> Metho<strong>de</strong> (grauer Kasten) an, die innerhalb <strong>de</strong>r<br />

Klasse Raumschiff <strong>de</strong>finiert wur<strong>de</strong>:<br />

26


Was erkennen wir? Der Metho<strong>de</strong>nkopf in Zeile 16 beginnt mit <strong>de</strong>m<br />

Zugriffsmodifizierer public, <strong>de</strong>r <strong>de</strong>n öffentlichen Zugriff auf die Metho<strong>de</strong><br />

erlaubt. An zweiter Position steht <strong>de</strong>r Rückgabetyp void, <strong>de</strong>r besagt, dass kein<br />

Rückgabewert an <strong>de</strong>n Aufrufer geliefert wird. Als nächstes kommt <strong>de</strong>r<br />

Metho<strong>de</strong>nname mit <strong>de</strong>r Parameterliste in <strong>de</strong>n run<strong>de</strong>n Klammern. Dort fin<strong>de</strong>t<br />

27


sich nur ein Parameter (Variable) <strong>de</strong>s Datentyps int. Rufen wir die Metho<strong>de</strong> z.B.<br />

mit <strong>de</strong>r folgen<strong>de</strong>n Anweisung<br />

meinSpee<strong>de</strong>r.setBesatzung(150);<br />

auf, wird <strong>de</strong>r Wert 150 als Argument <strong>de</strong>m Parameter intAnzahl übergeben.<br />

Die if-Anweisung überprüft, ob sich <strong>de</strong>r Wert innerhalb <strong>de</strong>r Grenzen von 20 bis<br />

200 befin<strong>de</strong>t. Liegt er außerhalb, wird die Instanzvariable intBesatzung auf<br />

<strong>de</strong>n Wert 0 gesetzt und eine entsprechen<strong>de</strong> Fehlermeldung auf <strong>de</strong>r Konsole<br />

ausgegeben. Bei Einhaltung <strong>de</strong>r gesetzten Grenzen wird <strong>de</strong>r übergebene Wert<br />

<strong>de</strong>r Variablen intAnzahl an die Instanzvariable intBesatzung übergeben<br />

(Zeile 27) und eine Bestätigung an die Konsole geschickt. Auf diese Weise<br />

kann es nie zu einer Überladung unseres Raumschiffs bezüglich <strong>de</strong>r<br />

Besatzungsanzahl kommen. Nach <strong>de</strong>r Eingabe <strong>de</strong>s Objektnamen mit<br />

nachfolgen<strong>de</strong>m Punktoperator zeigt Ihnen übrigens IntelliSense wie<strong>de</strong>r die Liste<br />

<strong>de</strong>r möglichen Member an:<br />

Kapselung<br />

Sie sehen, dass die Metho<strong>de</strong> in ihrer Funktion als Kontrollinstanz arbeitet und<br />

somit die Objektintegrität sicherstellt. In <strong>de</strong>r OOP wird dieses Prinzip<br />

Kapselung genannt. Vielleicht ist Ihnen aufgefallen, dass durch das Än<strong>de</strong>rn <strong>de</strong>s<br />

Zugriffsmodifizierers von public auf private, die Instanzvariable<br />

intBesatzung nicht mehr in <strong>de</strong>r Auswahlliste erscheint. Hier zur Erinnerung<br />

noch einmal die Be<strong>de</strong>utung <strong>de</strong>r Icons:<br />

28


Icon<br />

Erklärung<br />

Signalisiert, dass es sich um eine Metho<strong>de</strong> han<strong>de</strong>lt<br />

Tab. 6: Iconerklärungen<br />

Wenn Sie eine Klasse erstellen, seien Sie bestrebt, die darin enthaltene<br />

Komplexität zu verbergen, zu kapseln. Jemand, <strong>de</strong>r die Klasse nutzt, benötigt<br />

keine Informationen über die internen Vorgänge. Der Zugang sollte über<br />

öffentliche Metho<strong>de</strong>n o<strong>de</strong>r die noch zu besprechen<strong>de</strong>n Eigenschaften erfolgen.<br />

Vielleicht haben Sie schon einmal <strong>de</strong>n Begriff Black-Box gehört. Es ist ein<br />

Gebil<strong>de</strong>, <strong>de</strong>ssen innerstes im Verbogenen liegt und wir wissen nur, dass es eine<br />

bestimmte Aufgabe zu erfüllen hat. Wie es sie erledigt, ist nicht bekannt und<br />

wir müssen es nicht unbedingt wissen. Die Hauptsache ist, dass die Black-Box<br />

funktioniert.<br />

Argument und Parameter<br />

Dotty: „So ganz habe ich <strong>de</strong>n Unterschied zwischen Argumenten und<br />

Parametern noch nicht verstan<strong>de</strong>n!“<br />

Beim Aufruf einer Metho<strong>de</strong>, können ihr Werte übergeben wer<strong>de</strong>n, mit <strong>de</strong>nen sie<br />

arbeitet. Diese bezeichnet man als Argumente. Die Metho<strong>de</strong> ihrerseits muss<br />

diese Argumente entgegen nehmen und in entsprechen<strong>de</strong>n Variablen speichern.<br />

Sie wer<strong>de</strong>n Parameter genannt.<br />

Argument<br />

150<br />

Parameter<br />

public void setBesatzung(int Anzahl)<br />

{<br />

...<br />

}<br />

Abb. 6:<br />

Argument und Parameter<br />

29


Mehrere Parameter<br />

Natürlich können wir die Parameterliste beliebig erweitern. Dazu wer<strong>de</strong>n die<br />

einzelnen Parameter durch Kommata von einan<strong>de</strong>r getrennt angegeben.<br />

Schauen Sie sich die Dimension <strong>de</strong>s Raumschiffs an, die ich <strong>de</strong>r Einfachheit<br />

halber auf Länge und Breite reduziert habe. Es mach wenig Sinn, je eine<br />

Metho<strong>de</strong> für die Länge bzw. für die Breite zu <strong>de</strong>finieren.<br />

30


Zeile<br />

Erklärung<br />

18 - 22 Definition <strong>de</strong>r Metho<strong>de</strong> setDimension(double, double). Beachten<br />

Sie bitte, dass für je<strong>de</strong>n Parameter, obwohl bei<strong>de</strong> <strong>de</strong>n gleichen Datentyp double<br />

besitzen, die explizite Angabe erfor<strong>de</strong>rlich ist. setDimension(double<br />

dblL, dblB) ist nicht zulässig!<br />

32 Aufruf <strong>de</strong>r Metho<strong>de</strong> setDimension(). Beachten Sie die Reihenfolge <strong>de</strong>r<br />

Argumente: Argument1 (300.5) wird an Parameter1 (dblL) bzw. Argument2 (76.7)<br />

an Parameter2 (dblB) übergeben.<br />

Tab. 7: Co<strong>de</strong>-Erläuterungen<br />

Call by value<br />

Beim Aufruf einer Metho<strong>de</strong> erfolgte die Übergabe eines o<strong>de</strong>r mehrerer<br />

Argumente bisher nach <strong>de</strong>m Prinzip <strong>de</strong>r Wertübergabe, auch call by value<br />

genannt. Dabei wer<strong>de</strong>n die Argumente <strong>de</strong>s Aufrufers in die entsprechen<strong>de</strong>n<br />

Parameter <strong>de</strong>r Metho<strong>de</strong> kopiert. Das folgen<strong>de</strong> Beispiel zeigt <strong>de</strong>n Aufruf <strong>de</strong>r<br />

Metho<strong>de</strong> swap, an die zwei Werte übergeben wer<strong>de</strong>n. Sie hat die Aufgabe, die<br />

bei<strong>de</strong>n Werte zu vertauschen. Jedoch fin<strong>de</strong>t <strong>de</strong>r Tausch nur innerhalb <strong>de</strong>r<br />

Metho<strong>de</strong> swap statt, und bezieht sich nur auf die lokalen Variablen intW1 und<br />

intW2. Es fin<strong>de</strong>t keine Rückkopplung an die bei<strong>de</strong>n Variablen intWert1 und<br />

intWert2 statt, die als Argumente <strong>de</strong>r Metho<strong>de</strong> swap eingesetzt wur<strong>de</strong>n.<br />

31


Deshalb lautet die Konsolen-Ausgabe:<br />

Wert1: 10<br />

Wert2: 20<br />

Wir sehen, dass die bei<strong>de</strong>n Werte nicht vertauscht wur<strong>de</strong>n. Wie schaffen wir es<br />

aber trotz<strong>de</strong>m, dass die Metho<strong>de</strong> swap die Aufgabe erfüllt?<br />

32


Call by reference<br />

Fügen wir <strong>de</strong>n Parametern <strong>de</strong>r Metho<strong>de</strong> swap jedoch das Schlüsselwort ref<br />

hinzu, än<strong>de</strong>rt sich das Verhalten <strong>de</strong>r Metho<strong>de</strong>.<br />

Zusätzlich muss <strong>de</strong>r Metho<strong>de</strong>naufruf dahingehend angepasst wer<strong>de</strong>n, dass dort<br />

ebenfalls das Schlüsselwort ref verwen<strong>de</strong>t wird.<br />

Die Konsolen-Ausgabe lautet jetzt:<br />

Wert1: 20<br />

Wert2: 10<br />

Doch wie kommt es zu dieser Wandlung? In diesem Fall wird nicht mit <strong>de</strong>n<br />

Kopien <strong>de</strong>r übergebenen Werte gearbeitet. Der Metho<strong>de</strong>naufruf übergibt die<br />

Speicheradressen (Referenz- o<strong>de</strong>r Verweisübergabe) <strong>de</strong>r Argumente an die<br />

Parameter, was be<strong>de</strong>utet, dass die Parameter als Aliasnamen angesehen wer<strong>de</strong>n<br />

können. Folgen<strong>de</strong> Punkte sind bei call by reference zu beachten:<br />

♦ Die Variablen in <strong>de</strong>r Parameterliste wer<strong>de</strong>n mit <strong>de</strong>m Schlüsselwort ref<br />

gekennzeichnet<br />

♦ Den Argumenten im Metho<strong>de</strong>naufruf muss ebenfalls das Schlüsselwort ref<br />

vorangestellt wer<strong>de</strong>n<br />

33


♦ Der o<strong>de</strong>r die Argumente müssen initialisiert sein<br />

♦ Die Übergabe einer Konstanten ist unzulässig. An<strong>de</strong>rnfalls erhalten Sie die<br />

Fehlermeldung :<br />

Der Vollständigkeit halber, möchte ich noch <strong>de</strong>n Parameter out ansprechen. Er<br />

arbeitet ähnlich, wie ref. Der Unterschied ist jedoch, dass beim Metho<strong>de</strong>naufruf<br />

an <strong>de</strong>n mit out <strong>de</strong>klariertem Parameter keine initialisierte Variable übergeben<br />

wer<strong>de</strong>n muss. Es wer<strong>de</strong>n also keine Daten an die Metho<strong>de</strong> übergeben, son<strong>de</strong>rn<br />

sie steht in <strong>de</strong>r Pflicht, diese zurück zu liefern.<br />

Wertrückgabe<br />

Sie haben gesehen, wie über eine öffentliche Metho<strong>de</strong> eine private<br />

Instanzvariable modifizieren wer<strong>de</strong>n kann. Natürlich ist <strong>de</strong>r umgekehrte Weg,<br />

das Abfragen einer Instanzvariablen, ebenso möglich. Fügen wir <strong>de</strong>r Klasse<br />

Raumschiff das folgen<strong>de</strong> Co<strong>de</strong>fragment hinzu, wird <strong>de</strong>r Wert von<br />

intBesatzung abgefragt.<br />

Was erkennen wir? Der Metho<strong>de</strong>nkopf in Zeile 33 beginnt mit <strong>de</strong>m<br />

Zugriffsmodifizierer public, <strong>de</strong>r <strong>de</strong>n öffentlichen Zugriff auf die Metho<strong>de</strong><br />

erlaubt. An zweiter Position steht <strong>de</strong>r Rückgabetyp int, <strong>de</strong>n die Metho<strong>de</strong><br />

zurückliefert. Als nächstes folgt <strong>de</strong>r Metho<strong>de</strong>nname, <strong>de</strong>ssen Parameterliste<br />

34


jedoch leer ist, da keine Wertübergabe erfolgen soll. In Zeile 35 benutzen wir<br />

das Schlüsselwort return. Es dient dazu, einen bestimmten Wert an <strong>de</strong>n<br />

Aufrufer zurück zuliefern. Die Syntax lautet:<br />

return Variable;<br />

o<strong>de</strong>r<br />

return Wert;<br />

Die folgen<strong>de</strong> Grafik veranschaulicht <strong>de</strong>n schreiben<strong>de</strong>n bzw. lesen<strong>de</strong>n Prozess<br />

auf das Objekt:<br />

35


Die Anweisung zum Abfragen <strong>de</strong>r Instanzvariablen lautet:<br />

Console.WriteLine(meinSpee<strong>de</strong>r.getBesatzung());<br />

Wissenswertes über return<br />

Unerreichbarer Co<strong>de</strong><br />

Vielleicht ist Ihnen in <strong>de</strong>n Sinn gekommen, dass Sie nach <strong>de</strong>m Zurückliefern<br />

<strong>de</strong>s Wertes von intBesatzung noch zusätzlich eine Information an die<br />

Konsole schicken sollten.<br />

Schon rein optisch gesehen (Schlangenlinien) muss am vorliegen<strong>de</strong>n Co<strong>de</strong><br />

etwas nicht stimmen. Zeile 35 liefert <strong>de</strong>n Wert von intBesatzung an <strong>de</strong>n<br />

Aufrufer zurück und verlässt damit augenblicklich die Metho<strong>de</strong>. Das be<strong>de</strong>utet<br />

natürlich, dass die Anweisung in Zeile 36 nie zur Ausführung gebracht wird.<br />

Fahren Sie mit <strong>de</strong>r Maus über die Schlangenlinien, lautet <strong>de</strong>r Hinweis:<br />

„Unerreichbarer Co<strong>de</strong> wur<strong>de</strong> ent<strong>de</strong>ckt.“<br />

return zwingend notwendig<br />

Wur<strong>de</strong> ein Rückgabetyp außer void vereinbart, so ist es zwingend notwendig,<br />

dass die Metho<strong>de</strong> mit return einen Wert zurückliefert. Fin<strong>de</strong>t innerhalb <strong>de</strong>r<br />

Metho<strong>de</strong> z.B. eine Verzweigung über die if-else-Anweisung statt, muss<br />

sichergestellt wer<strong>de</strong>n, dass je<strong>de</strong>r mögliche Ausführungszweig eine return-<br />

Anweisung bereitstellt.<br />

36


Innerhalb <strong>de</strong>r Metho<strong>de</strong> befin<strong>de</strong>t eine Kontrollstruktur, die je nach<br />

Wahrheitsgehalt einen von bei<strong>de</strong>n Co<strong>de</strong>pfa<strong>de</strong>n ausführt. Da jedoch nur <strong>de</strong>r if-<br />

Zweig die Bedingung, einen Rückgabewert zu liefern, erfüllt (Zeile 36), wür<strong>de</strong><br />

es beim Eintritt in <strong>de</strong>n else-Zweig ein Problem geben. Deshalb erhalten wir die<br />

folgen<strong>de</strong> Fehlermeldung:<br />

Sorgen Sie dafür, dass alle möglichen Ausführungspfa<strong>de</strong> in einem solchen Fall<br />

einen Rückgabewert an <strong>de</strong>n Aufrufer liefern.<br />

return auch bei void<br />

Soll eine Metho<strong>de</strong> keinen Wert an <strong>de</strong>n Aufrufer zurück liefern, setzt man <strong>de</strong>n<br />

Rückgabetyp auf void, was übersetzt leer be<strong>de</strong>utet. Eine return-Anweisung ist<br />

dadurch nicht notwendig bzw. optional. Dennoch kann die Metho<strong>de</strong> mit return,<br />

jedoch ohne Angabe eines Rückgabewertes, vorzeitig verlassen wer<strong>de</strong>n.<br />

Zusammenfassend be<strong>de</strong>utet dies, dass eine Metho<strong>de</strong>, die void als<br />

Rückgabetype hat, entwe<strong>de</strong>r durch das Erreichen <strong>de</strong>r schließen<strong>de</strong>n<br />

geschweiften Klammer o<strong>de</strong>r durch eine return-Anweisung verlassen wer<strong>de</strong>n<br />

kann.<br />

37


Metho<strong>de</strong>nüberladung<br />

In <strong>C#</strong> können Metho<strong>de</strong>n überla<strong>de</strong>n wer<strong>de</strong>n, was be<strong>de</strong>utet, dass mehrere mit<br />

gleichem Namen existieren.<br />

Dotty: „Können wir dann immer noch von Ein<strong>de</strong>utigkeit sprechen?“<br />

Es existiert natürlich ein Unterscheidungsmerkmal. Wenn <strong>de</strong>r Name nicht zur<br />

Differenzierung herangezogen wer<strong>de</strong>n kann, konzentrieren wir uns auf die<br />

Parameterliste. Sie muss sich in <strong>de</strong>n einzelnen gleichnamigen Metho<strong>de</strong>n<br />

unterschei<strong>de</strong>n. Dabei dürfen sich die Metho<strong>de</strong>n nicht nur im möglicherweise<br />

vorhan<strong>de</strong>nen Rückgabetyp unterschei<strong>de</strong>n.<br />

38


Die Konsolen-Ausgabe lautet:<br />

Parameterlos<br />

Ein int-Parameter<br />

Zwei int-Parameter<br />

Ein int- / ein double-Parameter<br />

Zeile<br />

Erklärung<br />

38 Aufruf <strong>de</strong>r Metho<strong>de</strong> ohne Parameter. Die Metho<strong>de</strong>n<strong>de</strong>finition in Zeile 13 fühlt sich<br />

39


aufgrund <strong>de</strong>s Fehlens jeglicher Argumente angesprochen.<br />

39 Aufruf <strong>de</strong>r Metho<strong>de</strong> mit einem Ganzzahl-Literal, welches als Datentyp int interpretiert<br />

wird. Die Metho<strong>de</strong>n<strong>de</strong>finition in Zeile 18 wird angesprungen, da sich in <strong>de</strong>ren<br />

Parameterliste eine Variable vom Datentyp int befin<strong>de</strong>t.<br />

40 Aufruf <strong>de</strong>r Metho<strong>de</strong> mit zwei Ganzzahl-Literalen. Die Metho<strong>de</strong>n<strong>de</strong>finition in Zeile 23<br />

fühlt sich angesprochen. Sie besitzt in ihrer Parameterliste zwei Variablen <strong>de</strong>s<br />

Datentyps int.<br />

41 Aufruf <strong>de</strong>r Metho<strong>de</strong> mit einem int bzw. double Wert. Die Metho<strong>de</strong>n<strong>de</strong>finition in Zeile<br />

28 wird angesprungen. Die Parameterliste enthält sowohl eine int-, als auch eine<br />

double-Variable.<br />

Tab. 8: Co<strong>de</strong>-Erläuterungen<br />

Dotty: „Kann man beim Aufruf einer Metho<strong>de</strong> erkennen, ob und wie oft sie<br />

überla<strong>de</strong>n ist?“<br />

Das ist möglich. Vielleicht ist es Ihnen schon beim Tippen <strong>de</strong>r Metho<strong>de</strong><br />

Console.WriteLine() aufgefallen. Nach <strong>de</strong>r Eingabe <strong>de</strong>s Namens, gefolgt von<br />

<strong>de</strong>r run<strong>de</strong>n öffnen<strong>de</strong>n Klammer, zeigt uns IntelliSense die folgen<strong>de</strong>n<br />

Informationen:<br />

Es existieren vier Metho<strong>de</strong>nüberladungen (1 von 4) wovon die erste<br />

parameterlose Version - zu erkennen am leeren run<strong>de</strong>n Klammernpaar - zur<br />

Auswahl angeboten wird. Sie haben jetzt die Möglichkeit mit <strong>de</strong>n Tasten<br />

Cursoroben bzw. Cursounten sich die einzelnen überla<strong>de</strong>nen Metho<strong>de</strong>n mit <strong>de</strong>ren<br />

Parameterliste anzuschauen:<br />

40


Dotty: „Ich verstehe <strong>de</strong>n Sinn <strong>de</strong>s Überla<strong>de</strong>ns noch nicht so ganz.“<br />

Kommen wir noch einmal zu <strong>de</strong>r schon angesprochenen Metho<strong>de</strong><br />

Console.WriteLine(...), die 19-fach überla<strong>de</strong>n ist. Sie ist so flexibel, dass sie als<br />

Argument die unterschiedlichsten Datentypen akzeptiert und über einen<br />

einzigen Namen aufzurufen ist. Wür<strong>de</strong>n die Möglichkeit <strong>de</strong>s Überla<strong>de</strong>ns in <strong>C#</strong><br />

nicht existieren, so müssten wir für je<strong>de</strong>n existieren<strong>de</strong>n Datentyp jeweils eine<br />

eigene Metho<strong>de</strong> schreiben, was zur Folge hätte, dass es unzählige Metho<strong>de</strong>n mit<br />

unterschiedlichen Namen geben wür<strong>de</strong>:<br />

♦ WriteLineByte(...)<br />

♦ WriteLineShort(...)<br />

♦ WriteLineInt(...)<br />

♦ usw.<br />

Könnten Sie sich alle möglichen Metho<strong>de</strong>n alleine für WriteLine merken? Ist<br />

natürlich machbar, doch recht ineffektiv. Durch die Metho<strong>de</strong>nüberladung wird<br />

die Sache enorm vereinfacht und durch die Reduzierung unterschiedlicher<br />

Metho<strong>de</strong>nnamen vor allen Dingen übersichtlicher. Wir übergeben beim Aufruf<br />

einen Wert, soll sich jemand an<strong>de</strong>res darum kümmern, die dazu passen<strong>de</strong><br />

Metho<strong>de</strong> aufzurufen.<br />

Beliebig viele Argumente<br />

Nach<strong>de</strong>m wir jetzt die Funktionsweise <strong>de</strong>r Metho<strong>de</strong>nüberladung kennen gelernt<br />

haben, sehen wir uns das folgen<strong>de</strong> Beispiel an. Es soll die Möglichkeit bieten,<br />

die Summe von verschie<strong>de</strong>nen Zahlen zu bil<strong>de</strong>n.<br />

41


Was erkennen wir? Es existieren 3 Metho<strong>de</strong>n mit Namen summe. Sie liefern<br />

jeweils die Summe <strong>de</strong>r übergebenen Argumente an <strong>de</strong>n Aufrufer zurück. Die<br />

Frage, die sich uns stellt ist: „Wie weit wollen wir das Spiel noch treiben?“ Ich<br />

meine damit die Anzahl <strong>de</strong>r überla<strong>de</strong>nen Metho<strong>de</strong>n, um auf möglichst viele<br />

Möglichkeiten in <strong>de</strong>r Anzahl <strong>de</strong>r Argumente reagieren zu können. Es gibt eine<br />

Alternative. Dazu existiert ein spezieller Parameter, <strong>de</strong>r durch das Schlüsselwort<br />

params gekennzeichnet wird.<br />

42


Die Konsolen-Ausgabe lautet:<br />

Summe ist: 0<br />

Summe ist: 21<br />

Summe ist: 10<br />

Summe ist: 17<br />

Durch <strong>de</strong>n Zusatz von params wird aus <strong>de</strong>m Parameter ein Array, auf das, wie<br />

schon gelernt, zugegriffen wer<strong>de</strong>n kann. Die foreach-Schleife spricht je<strong>de</strong>s<br />

Element <strong>de</strong>s Arrays an und in Zeile 17 wird die Summe gebil<strong>de</strong>t. Zeile 19 liefert<br />

das Ergebnis an <strong>de</strong>n Aufrufer zurück. Wie Sie in Zeile 27 sehen, können auch<br />

keine Argumente übergeben wer<strong>de</strong>n.<br />

43


Konstruktoren (spezialisierte Metho<strong>de</strong>n)<br />

Sie bekommen als Captain ihres neuen Raumschiffs meinSpee<strong>de</strong>r die Aufgabe,<br />

eine nahe gelegene befreun<strong>de</strong>te Kolonie aufzusuchen, in <strong>de</strong>r es einen<br />

feindlichen Übergriff aus <strong>de</strong>m Nachbarsektor gegeben hat. Natürlich verlassen<br />

sie sich darauf, dass ihre Bewaffnung in Form von Photonentorpedos in<br />

ausreichen<strong>de</strong>r Stückzahl zur Verfügung steht. Auf halber Strecke müssen sie<br />

sich lei<strong>de</strong>r vom Gegenteil überzeugen lassen. Wie konnte das passieren? Der<br />

folgen<strong>de</strong> Source-Co<strong>de</strong> konzentriert sich nur auf die Instanzvariable<br />

intPhotonentorpedos und lässt die restlichen Eigenschaften außen vor.<br />

44


Die Konsolen-Ausgabe bringt es ans Tageslicht:<br />

Anzahl <strong>de</strong>r Torpedos: 0<br />

Es wur<strong>de</strong> in <strong>de</strong>r Hektik einfach vergessen, die Metho<strong>de</strong> setPhotonentorpedos<br />

nach <strong>de</strong>m Generieren <strong>de</strong>s Raumschiffs mit entsprechen<strong>de</strong>r Anzahl aufzurufen.<br />

Wie können wir dieses Manko beheben? Am sichersten wäre ein<br />

Automatismus, <strong>de</strong>r nach <strong>de</strong>r Instanziierung <strong>de</strong>s Objektes eine bestimmte<br />

Metho<strong>de</strong> aufruft, die eine Vorinitialisierung vornimmt, so dass z.B. die<br />

Instanzvariablen einen <strong>de</strong>finierten, initialen Startwert bekommen. Das Problem,<br />

welches uns dabei entgegenschlägt ist aber: Je<strong>de</strong>r Programmierer könnte diese<br />

Metho<strong>de</strong> an<strong>de</strong>rs benennen. Wie stellen wir aufgrund dieser Problematik die<br />

Initialisierung <strong>de</strong>s Objektes sicher? Die Antwort ist recht simpel. Die Metho<strong>de</strong><br />

besitzt <strong>de</strong>n gleichen Namen wie die Klasse und wird somit zum Konstruktor.<br />

Die wörtliche Übersetzung aus <strong>de</strong>m Englischen heißt „Bauherr“.<br />

Er wird bei <strong>de</strong>r Instanziierung eines Objektes automatisch aufgerufen.<br />

Die Syntax lautet:<br />

Zugriffstyp Klassenname([Parameterliste])<br />

{<br />

}<br />

// Anweisung(en)<br />

Konstruktoren besitzen übrigens keinen Rückgabetyp (void inbegriffen).<br />

45


Dotty: „Das verstehe ich nicht. Ein Konstruktor ist doch auch eine art<br />

Metho<strong>de</strong>, die unter gewissen Umstän<strong>de</strong>n eine Berechnung durchführen und<br />

das Ergebnis an <strong>de</strong>n Aufrufer zurückliefern kann.“<br />

Und das ist genau <strong>de</strong>r Kasus Knacktus! Wodurch bzw. durch wen wird ein<br />

Konstruktor aufgerufen? Nicht etwa durch einen expliziten Aufruf von außen.<br />

Der Aufruf erfolgt bei <strong>de</strong>r Instanziierung, also zum Zeitpunkt <strong>de</strong>r<br />

Objektgenerierung. An wen sollte da ein Rückgabewert zurück geliefert<br />

wer<strong>de</strong>n? Schauen Sie sich <strong>de</strong>n modifizierten Source-Co<strong>de</strong> inklusive<br />

Konstruktor an:<br />

46


Die Konsolen-Ausgabe lautet:<br />

Konstruktor-Aufruf.<br />

Anzahl <strong>de</strong>r Torpedos: 2500<br />

Konstruktorüberladung<br />

Das Überla<strong>de</strong>n eines Konstruktors ist vergleichbar mit <strong>de</strong>m einer Metho<strong>de</strong>. Wir<br />

haben schon gesehen, dass mit einem Konstruktor ein Objekt initialisiert<br />

wer<strong>de</strong>n kann. Durch unterschiedliche Konstruktoren haben wir jetzt die<br />

Möglichkeit, verschie<strong>de</strong>ne Objekte mit abweichen<strong>de</strong>n Startwerten bei <strong>de</strong>r<br />

Instanziierung zu versehen. Der parameterlose Konstruktor aus <strong>de</strong>m letzten<br />

Beispiel sorgte dafür, dass die Bestückung bezüglich <strong>de</strong>r Anzahl <strong>de</strong>r<br />

Photonentorpedos automatisch auf <strong>de</strong>n Wert 2500 gesetzt wur<strong>de</strong>. Überla<strong>de</strong>n wir<br />

<strong>de</strong>n Konstruktor mit <strong>de</strong>r folgen<strong>de</strong>n Definition<br />

können wir mit <strong>de</strong>r Zeile<br />

unser Raumschiff entsprechend bestücken.<br />

48


Standardkonstruktor<br />

Sollten Sie keinen Konstruktor <strong>de</strong>finiert haben, übernimmt <strong>C#</strong> für Sie die<br />

Aufgabe und generiert automatisch einen parameterlosen Standardkonstruktor.<br />

Er ist u.a. dafür verantwortlich, dass die in <strong>de</strong>r Klasse aufgeführten<br />

Instanzvariablen mit einem Standardwert initialisiert wer<strong>de</strong>n. Wenn jedoch ein<br />

eigener parametrisierter Konstruktor hinzufügt wird, ist <strong>de</strong>r Standardkonstruktor<br />

nicht mehr existent. Sie müssen ihn notfalls explizit hinzufügen. Der folgen<strong>de</strong><br />

Co<strong>de</strong> enthält einen parametrisierten Konstruktor (Zeile 14 bis 17), jedoch keine<br />

explizite Definition für <strong>de</strong>n Standardkonstruktor.<br />

49


Die Schlangenlinien in Zeile 29 weisen uns unbarmherzig auf einen erkannten<br />

Fehler hin.<br />

Das be<strong>de</strong>utet, dass es keinen Konstruktor gibt, <strong>de</strong>r 0 Argumente annimmt,<br />

sprich: <strong>de</strong>r Standardkonstruktor fehlt. Falls er sowieso nichts machen soll, fügen<br />

Sie einfach folgen<strong>de</strong>n Co<strong>de</strong> ein:<br />

Konstruktor ruft Konstruktor<br />

Existieren mehrere überla<strong>de</strong>ne Konstruktoren, so kann es sinnvoll sein, wenn<br />

ein Konstruktor <strong>de</strong>n an<strong>de</strong>ren aufruft. Wird <strong>de</strong>r parameterlose Konstruktor<br />

aufgerufen, können wir ihn ihm eine Objektinitialisierung mit vor<strong>de</strong>finierten<br />

Werten festlegen. Existiert ein überla<strong>de</strong>ner, parametrisierter Konstruktor, <strong>de</strong>r<br />

ebenfalls für die Objektinitialisierung erstellt wur<strong>de</strong>, kann <strong>de</strong>r parameterlose<br />

Konstruktor <strong>de</strong>n parametrisierten ausführen, um gleichlauten<strong>de</strong>n Co<strong>de</strong> in bei<strong>de</strong>n<br />

Konstruktoren zu vermei<strong>de</strong>n. Schauen Sie sich das folgen<strong>de</strong> Beispiel an:<br />

50


Der parameterlose Konstruktor in Zeile 16 wird durch die Objektgenerierung<br />

aus Zeile 33 aufgerufen. Er führt seinerseits durch das Schlüsselwort this <strong>de</strong>n<br />

parametrisierten Konstruktor aus Zeile 21 aus, in <strong>de</strong>m er ihm die Werte in Form<br />

einer Arumentenliste (250, 300.5, 150.4) übergibt. Sie sehen auch, dass <strong>de</strong>r<br />

Konstruktorrumpf zwischen <strong>de</strong>n Zeilen 17 und 19 leer ist, da die Initialisierung<br />

an an<strong>de</strong>rer Stelle vorgenommen wird.<br />

51


this<br />

Sie erinnern sich bestimmt an die Metho<strong>de</strong> setDimension, mit <strong>de</strong>ren Hilfe wir<br />

die gekapselten Instanzvariablen dblLaenge und dblBreite initialisiert haben.<br />

Die Parameter dblL und dblB waren, wie Sie sicher vermutet haben, eine<br />

Abkürzung <strong>de</strong>r Instanzvariablen, um <strong>de</strong>ren Verwendungszweck <strong>de</strong>utlicher zu<br />

machen. Was spricht aber dagegen, wenn wir <strong>de</strong>n Parametern die gleichen<br />

Namen vergeben, wie die <strong>de</strong>r Instanzvariablen?<br />

Wenn Sie sich die Zuweisungen in <strong>de</strong>n Zeilen 18 und 19 anschauen, sollten bei<br />

Ihnen die Alarmglocken läuten. Syntaktisch gesehen ist alles in bester Ordnung,<br />

doch was wollen wir eigentlich bezwecken? Die übergebenen Argumente sollen<br />

in <strong>de</strong>n Parametern <strong>de</strong>r Metho<strong>de</strong> gespeichert und mittels Zuweisung an die<br />

privaten Instanzvariablen übergeben wer<strong>de</strong>n. Innerhalb <strong>de</strong>r Metho<strong>de</strong> wird direkt<br />

52


auf die <strong>de</strong>finierten Parameter dblLaenge bzw. dblBreite zugegriffen. Wie aber<br />

teilen wir <strong>de</strong>m Compiler mit, dass er auf die gleich lauten<strong>de</strong>n Instanzvariablen<br />

zugreifen soll? Jetzt kommt this zum Einsatz. Es dienst als Referenz auf das<br />

aktuelle Objekt. Modifizieren wir also die Zeilen 18 und 19 wie folgt:<br />

Auf <strong>de</strong>r linken Seite <strong>de</strong>r Zuweisungen wur<strong>de</strong>n die Variablennamen um das<br />

Schlüsselwort this erweitert. In dieser Kombination bezieht sich <strong>de</strong>r Ausdruck<br />

nicht mehr auf die Parameter <strong>de</strong>r Metho<strong>de</strong>, son<strong>de</strong>rn auf die Instanzvariablen.<br />

Garbage Collection<br />

53


Generieren wir über das Schlüsselwort new ein neues Objekt, wird ihm auf <strong>de</strong>m<br />

Heap zur Laufzeit ein Stückchen von freiem Speicher zugewiesen. Wie wir alle<br />

wissen, ist unser lokal zur Verfügung stehen<strong>de</strong>r Speicher zwar in <strong>de</strong>n letzten<br />

Jahren stetig gewachsen, doch <strong>de</strong>r Vorrat ist nicht unerschöpflich. In einer<br />

Anwendung wer<strong>de</strong>n Objekte dynamisch erstellt, können aber nach einer<br />

gewissen Zeit u.U. nicht mehr von Nutzen sein, da sie nicht mehr referenziert<br />

wer<strong>de</strong>n. Können wir ein solches Objekt nicht mehr über einen gültigen Verweis<br />

ansprechen, ist es nutzlos gewor<strong>de</strong>n und blockiert <strong>de</strong>n kostbaren Speicher, <strong>de</strong>r<br />

an an<strong>de</strong>rer Stelle benötigt wird. Die Frage, die sich uns stellt ist: „Wie<br />

entledigen wir uns <strong>de</strong>r Objektleichen?“ Tja, da können wir gar nichts machen.<br />

Nein wirklich, <strong>de</strong>nn das .NET Framework ist mit einer automatischen<br />

Speicherverwaltung ausgerüstet, welche sich <strong>de</strong>r verwaisten Objekte annimmt.<br />

Der Fachbegriff hierfür ist Garbage Collection (GC). Sie ist Bestandteil <strong>de</strong>r<br />

Common Language Runtime (CLR), arbeitet als Mülldienstleitster auf<br />

Speicherebene im Hintergrund und spürt alle nicht mehr benötigten Objekte auf,<br />

die daraufhin aus <strong>de</strong>m Speicher entfernt wer<strong>de</strong>n, damit dieser bereit für die<br />

Aufnahme neuer Objekte ist. Danach erfolgt eine Reorganisation. Die GC ist<br />

ständig bestrebt, dass immer genug Speicher-Ressourcen für künftige<br />

Anfor<strong>de</strong>rungen zur Verfügung stehen und kein Engpass aufgrund von<br />

Speicherleichen (Memory Leaks) entsteht.<br />

Dotty: „Das be<strong>de</strong>utet also, dass sie sofort zuschlägt und mit <strong>de</strong>m großen<br />

Besen vorbeikommt, wenn ein Objekt nicht mehr benötigt wird.“<br />

Dem ist nicht so. Die Garbage Collection legt ein, wie man so schön sagt, nicht<br />

<strong>de</strong>terministisches Verhalten an <strong>de</strong>n Tag, was be<strong>de</strong>utet, dass es nicht<br />

vorhersehbar ist, wann sie zuschlägt. Wür<strong>de</strong> sie sofort in Aktion treten, wenn<br />

auf ein Objekt kein gültiger Verweis mehr existierte, müsste eines natürlich<br />

sicher gestellt sein: Die Garbage Collection muss ständig aktiv sein. Sie können<br />

sich sicherlich vorstellen, dass das mit einer gewissen Rechenleistung<br />

verbun<strong>de</strong>n ist, die bei stetiger Ausführung zu Performanceeinbußen führt. Es<br />

gibt aber <strong>de</strong>nnoch ein Kriterium, das ihn dazu bewegt, aus seinem normalen<br />

Trott heraus, seine Aufräumarbeit zu beginnen. Wenn die freien<br />

Speicherressourcen ein gewissen Wert unterschreiten, so dass ein Engpass<br />

entstün<strong>de</strong>, wir die Suche gestartet.<br />

54


Destruktoren<br />

Sie haben die Baumeister <strong>de</strong>r Objekte, die Konstruktoren, kennen gelernt. Dazu<br />

gibt es ein passen<strong>de</strong>s Gegenstück. Den Destruktor. Es ist eine Metho<strong>de</strong>, die<br />

kurz bevor die Garbage Collection das Objekt aus <strong>de</strong>m Speicher entfernt,<br />

aufgerufen wird. Sie trägt <strong>de</strong>n gleichen Namen wie die Klasse, ganz gleich <strong>de</strong>m<br />

<strong>de</strong>r Konstruktor<strong>de</strong>finition, jedoch mit <strong>de</strong>m vorangestellten Til<strong>de</strong>-Zeichen ~.<br />

Der Destruktor besitzt keinen Rückgabetyp.<br />

Die Syntax lautet:<br />

~Klassenname()<br />

{<br />

}<br />

// Anweisung(en)<br />

Platzieren Sie <strong>de</strong>n Co<strong>de</strong> innerhalb <strong>de</strong>r Metho<strong>de</strong>, <strong>de</strong>r kurz vor <strong>de</strong>r Entfernung <strong>de</strong>s<br />

Objektes aus <strong>de</strong>m Speicher ausgeführt wer<strong>de</strong>n soll.<br />

55


Zeile<br />

Erklärung<br />

13 - 16 Konstruktor<strong>de</strong>finition<br />

18 - 21 Destruktor<strong>de</strong>finition<br />

27 Instanziierung <strong>de</strong>r Objektes meinSpee<strong>de</strong>r (Impliziter Aufruf <strong>de</strong>s Konstruktors)<br />

56


28 Objektfreigabe mittels Zuweisung durch null. Nach dieser Anweisung wird auf das<br />

Drücken <strong>de</strong>r Enter - Taste gewartet. Sie sehen, dass zu diesem Zeitpunkt <strong>de</strong>r<br />

Destruktor noch nicht aufgerufen wur<strong>de</strong>. (Keine Konsolenausgabe „Destruktoraufruf.“)<br />

34 Explizites Anstoßen <strong>de</strong>s Garbage Collectors (Aufruf <strong>de</strong>s Destruktors)<br />

Tab. 9: Co<strong>de</strong>-Erläuterungen<br />

Es existiert eine statische Metho<strong>de</strong> GC.Collect(), mit ihrer Hilfe die<br />

Garbage Collection explizit angestoßen wer<strong>de</strong>n kann.<br />

Kommen Sie jetzt bitte nicht auf die I<strong>de</strong>e, diese Metho<strong>de</strong> - für alle Fälle -<br />

mehrfach in Ihrer Anwendung aufzurufen, nur damit alle nicht mehr benötigten<br />

Objekte sofort gelöscht wer<strong>de</strong>n. Die Konsequenz dürfte Ihnen bekannt sein.<br />

Dotty: „Was passiert eigentlich, wenn ein einzelnes Objekt mehrere Verweise<br />

besitzt und nur einer davon wegfällt?“<br />

Existieren mehrere Verweise auf ein Objekt, so wird dieses von <strong>de</strong>r Garbage<br />

Collection nur erfasst, wenn <strong>de</strong>r letzte Verweis verschwun<strong>de</strong>n ist. Fügen wir<br />

eine zusätzliche Co<strong>de</strong>zeile (Zeile 29) ein, die eine zweite Referenz auf das<br />

Objekt generiert,<br />

und kappen <strong>de</strong>n ersten Verweis meinSpee<strong>de</strong>r in Zeile 30, verbleibt immer noch<br />

<strong>de</strong>r Verweis <strong>de</strong>inSpee<strong>de</strong>r, um auf das Objekt zuzugreifen. Die Garbage<br />

Collection wird bei diesem Objekt nicht aktiv.<br />

57


Vielleicht trägt das folgen<strong>de</strong> Bild auch ein wenig zum Verständnis bei.<br />

Eigenschaften<br />

Wenn es darum ging, auf eine geschützte, mit private <strong>de</strong>klarierte<br />

Instanzvariable zuzugreifen, haben wir jeweils eine Metho<strong>de</strong> zum Abfragen<br />

bzw. zum Modifizieren genutzt. Um die bei<strong>de</strong>n namentlich zu unterschei<strong>de</strong>n,<br />

nutzten wir das Präfix get (z.B. getBesatzung) für das Abfragen und set<br />

(z.B. setBesatzung) für das Modifizieren.<br />

58


Es wäre bestimmt einfacher und wünschenswert, müssten wir uns nicht zwei<br />

unterschiedliche Namen für <strong>de</strong>n Zugriff auf die Instanzvariable merken. Da wir<br />

die Kapselung <strong>de</strong>r Daten nicht aufweichen wollen, ermöglichen wir <strong>de</strong>n Zugriff<br />

auf die geschützten, mit private <strong>de</strong>klarierten Instanzvariablen nur über<br />

öffentliche Metho<strong>de</strong>n. Das ermöglicht uns, wie schon erwähnt, eine Kontrolle,<br />

<strong>de</strong>r an das Objekt herangetragenen Daten und bewart die Objektintegrität. In <strong>C#</strong><br />

gibt es einen speziellen Typ von Metho<strong>de</strong>: Die Eigenschaft (engl. Property). Die<br />

Syntax lautet:<br />

59


Zugriffstyp Rückgabetyp Name<br />

{<br />

get<br />

{<br />

// Anweisung(en)<br />

}<br />

set<br />

{<br />

// Anweisung(en)<br />

}<br />

}<br />

60


Metho<strong>de</strong><br />

get<br />

set<br />

Erklärung<br />

Liefert ein Wert zurück<br />

Modifiziert einen Wert und nutzt die implizit <strong>de</strong>finierte Variable value<br />

Die Metho<strong>de</strong>n wer<strong>de</strong>n auch als getter- bzw. setter-Metho<strong>de</strong>n bezeichnet. Wie<br />

Sie in Zeile 26 sehen, erfolgt die Wertzuweisung mit <strong>de</strong>m Zuweisungsoperator<br />

=, <strong>de</strong>r auch bei Variablenzuweisungen Verwendung fin<strong>de</strong>t. Die Abfrage <strong>de</strong>r<br />

Instanzvariablen, die in Zeile 27 statt fin<strong>de</strong>t, erfolgt über <strong>de</strong>nselben Ausdruck.<br />

Zusammenfassend können wir sagen, dass das Verhalten von Eigenschaften<br />

mit <strong>de</strong>r von öffentlichen, mit public <strong>de</strong>klarierten Instanzvariablen zu<br />

vergleichen ist.<br />

Haben wie eine Eigenschaft erstellt, wird diesem Element im Kontext <strong>de</strong>r<br />

Klassenumgebung ein neues Icon zugewiesen.<br />

Icon<br />

Erklärung<br />

Tab. 10:<br />

Signalisiert, dass es sich um eine Eigenschaft (Property) han<strong>de</strong>lt<br />

Iconerklärungen<br />

Führen Sie sich <strong>de</strong>n Unterschied in <strong>de</strong>n Aufrufen von Metho<strong>de</strong>n und<br />

Eigenschaften noch einmal vor Augen:<br />

Metho<strong>de</strong><br />

meinSpee<strong>de</strong>r.setBesatzung(400);<br />

Eigenschaft meinSpee<strong>de</strong>r.Besatzung = 400;<br />

Read-Only<br />

Sie können <strong>de</strong>n Zugriff auf die privaten Daten über eine Eigenschaft<br />

reglementieren, in <strong>de</strong>m Sie entwe<strong>de</strong>r die get- o<strong>de</strong>r die set-Metho<strong>de</strong> weglassen.<br />

61


Ist nur eine get-Metho<strong>de</strong> vorhan<strong>de</strong>n, haben Sie auch nur die Möglichkeit, Daten<br />

zu lesen. Wir nennen dies Read-Only (nur lesen).<br />

Write-Only<br />

Im Gegensatz dazu können wir mit <strong>de</strong>m alleinigen Vorhan<strong>de</strong>nsein einer set-<br />

Metho<strong>de</strong> nur das Modifizieren gestattet. Es wird Write-Only (nur schreiben)<br />

genannt.<br />

Dotty: „Ich verstehe zwar die Unterschie<strong>de</strong> in <strong>de</strong>r Implementierung, doch für<br />

welche Variante soll ich mich entschei<strong>de</strong>n?“<br />

Die Antwort darauf ist nicht einfach und im En<strong>de</strong>ffekt muss je<strong>de</strong>r für sich<br />

entschei<strong>de</strong>n, ob er <strong>de</strong>n Schreib/Lesezugriff auf private Daten lieber über zwei<br />

Metho<strong>de</strong>n mit unterschiedlichen Namen o<strong>de</strong>r über eine einzige Eigenschaft<br />

realisieren möchte. Falls Sie sich grundsätzlich für Metho<strong>de</strong>n entschei<strong>de</strong>n,<br />

sollten Sie be<strong>de</strong>nken, dass die Anzahl <strong>de</strong>r Objekt-Member natürlich verdoppelt<br />

wird. Das trägt u.U. nicht gera<strong>de</strong> zur besseren Übersicht bei.<br />

Konstanten<br />

Möchten Sie zu Beginn einer Anwendung einen o<strong>de</strong>r mehrere Werte festlegen,<br />

die zur Laufzeit nicht geän<strong>de</strong>rt wer<strong>de</strong>n dürfen, sollten Sie Konstanten<br />

<strong>de</strong>finieren. Die Kreiszahl Pi wür<strong>de</strong> in diese Kategorie fallen. Stellen Sie sich<br />

vor, dass durch irgen<strong>de</strong>inen dummen Zufall Pi einen an<strong>de</strong>ren Wert als<br />

62


3,141592... bekommen wür<strong>de</strong>. Nicht auszu<strong>de</strong>nken, welchen Aufstand die Kreise<br />

anzetteln wür<strong>de</strong>n. Die Syntax lautet:<br />

Zugriffstyp const Datentyp Name = Wert;<br />

Proben Sie <strong>de</strong>nnoch <strong>de</strong>n Aufstand und wollen mit aller Macht eine Än<strong>de</strong>rung,<br />

bekommen Sie die Quittung:<br />

Icon<br />

Erklärung<br />

Tab. 11:<br />

Signalisiert, dass es sich um eine Konstante han<strong>de</strong>lt<br />

Iconerklärungen<br />

Vererbung<br />

Grundlagen<br />

Kommen wir jetzt zu einem Kapitel, das sich mit <strong>de</strong>r Vererbung in <strong>C#</strong> befasst.<br />

Es geht dabei um ein Konzept in <strong>de</strong>r OOP, welches es ermöglicht, vorhan<strong>de</strong>nen<br />

Co<strong>de</strong> einer Klasse in einer abgeleiteten, Klasse wie<strong>de</strong>r zu verwen<strong>de</strong>n. Die<br />

abgeleitete Klasse - wir nennen sie mal Kindklasse - erbt sozusagen die<br />

Metho<strong>de</strong>n und Eigenschaften <strong>de</strong>r Basisklasse. Wir arbeiten also nach <strong>de</strong>m<br />

Motto: „Warum das Rad neu erfin<strong>de</strong>n?“ Nutzen wir die vorhan<strong>de</strong>ne<br />

63


Funktionalität einer Basisklasse und erweitern diese nach unseren Wünschen,<br />

um die notwendigen Aspekte in einer spezialisierten Kindklasse. Sehen wir uns<br />

das wie<strong>de</strong>r am Beispiel unserer Raumflotte an. Sie besteht natürlich nicht nur<br />

aus Kampfschiffen. Da gibt es z.B. noch Transport- o<strong>de</strong>r Forschungsschiffe. Die<br />

Frage, die wir uns stellen sollten ist: „Welche Eigenschaften haben alle Schiffe<br />

gemeinsam und in welchen Punkten unterschei<strong>de</strong>n sie sich?“ Die folgen<strong>de</strong>n<br />

Auflistungen <strong>de</strong>r Eigenschaften beschränken sich nur auf das Wesentlichste, um<br />

das Beispiel so knapp und einfach wie möglich zu halten:<br />

Kampfschiff Transportschiff Forschungsschiff<br />

Triebwerke Triebwerke Triebwerke<br />

Besatzung Besatzung Besatzung<br />

Photonentorpedos Lagerräume Forschungseinrichtung<br />

Quantentorpedos<br />

Andockschleusen<br />

Tab. 12: Raumschiff-Typen<br />

Ableiten von einer Basisklasse<br />

Sie sehen, dass die ersten bei<strong>de</strong>n Zeilen die Eigenschaften enthalten, die bei<br />

allen drei Schiffs-Typen gleich lauten. Alle nachfolgen<strong>de</strong>n Zeilen beschreiben<br />

Spezialisierungen <strong>de</strong>s jeweiligen Schiffs-Typ. Es liegt also nahe, die<br />

Gemeinsamkeiten, sprich die Schnittmenge, in eine Basisklasse auszulagern,<br />

um sie nicht in je<strong>de</strong>r Raumschiffklasse gleichermaßen zu benennen<br />

(Redundanter Co<strong>de</strong>). Etwaige Än<strong>de</strong>rungen bzw. Verbesserungen in <strong>de</strong>r<br />

Basisklasse kommen durch diese Auslagerung allen abgeleiteten Klassen zu<br />

Gute.<br />

64


Wir können die Abhängigkeit bzw. hierarchische Struktur in einem<br />

Klassendiagramm darstellen. Die Spitze <strong>de</strong>s Pfeils zeigt dabei auf die<br />

Basisklasse. (UML-Notation)<br />

Die Kodierung <strong>de</strong>r Basisklasse lautet <strong>de</strong>mnach:<br />

65


So weit so gut. Nun erschaffen wir exemplarisch ein Raumschiff, welches sich<br />

<strong>de</strong>r Eigenschaften <strong>de</strong>r Basisklasse bedient, jedoch einige ihm eigene<br />

Spezialisierungen hinzufügt. Der neue Typ soll Kampfschiff lauten. Bei <strong>de</strong>r<br />

Klassen<strong>de</strong>finition müssen wir aber zum Ausdruck bringen, dass die Ableitung<br />

von <strong>de</strong>r Basisklasse Raumschiff erfolgen soll. Das wird mit <strong>de</strong>m<br />

Doppelpunktoperator : und <strong>de</strong>r nachfolgend aufgeführten Basisklasse erreicht.<br />

Generieren Sie jetzt ein neues Kampfschiff, so bietet Ihnen IntelliSense die<br />

Instanzvariablen intBesatzung und intTriebwerke <strong>de</strong>r Basisklasse<br />

Raumschiff ebenso wie intPhotonentorpedos und<br />

intQuantentorpedos <strong>de</strong>r Kindklasse Kampfschiff zur Auswahl an.<br />

66


Eine abgeleitete Klasse ist in <strong>de</strong>r Regel spezialisierter und enthält mehr<br />

Funktionalität als ihre Basisklasse. Sie erhält Zugriff auf alle nicht privaten<br />

Member <strong>de</strong>r Basisklasse und auf alle in ihr selbst <strong>de</strong>finierten.<br />

Dotty: „Mit <strong>de</strong>r Kapselung ist es bei diesem Beispiel ja nicht weit her. Alle<br />

Eigenschaften sind direkt zu Manipulieren, so dass die Objektintegrität<br />

potentiell gefähr<strong>de</strong>t ist.“<br />

Vollkommen korrekt erkannt! Das folgen<strong>de</strong> Beispiel zeigt die Modifikation <strong>de</strong>s<br />

Programms dahingehend, dass die Kapselung wie<strong>de</strong>r aktiviert wird. Der Zugriff<br />

ist ausschließlich <strong>de</strong>n öffentlichen Metho<strong>de</strong>n gestattet. Die als private<br />

<strong>de</strong>klarierten Member sind in <strong>de</strong>r abgeleiteten Klasse nicht sichtbar.<br />

67


IntelliSense zeigt uns, dass nur auf mit public <strong>de</strong>klarierte Member <strong>de</strong>r Basisbzw.<br />

Kindklasse zugegriffen wer<strong>de</strong>n kann.<br />

Kindklasse ruft Basisklasse<br />

Dotty: „Wie können wir <strong>de</strong>r Kindklasse erlauben, direkt auf private Member<br />

<strong>de</strong>r Basisklasse zuzugreifen, ohne die Kapselung mit public aufzuweichen?“<br />

Wir stecken ein wenig in einer Zwickmühle. Der Zugriffsmodifizierer public ist<br />

zu lasch in seinen Restriktionen, wohingegen private es etwas zu weit treibt.<br />

Die Lösung <strong>de</strong>s Problems ist ein bisher unbekannter Zugriffsmodifizierer, <strong>de</strong>r<br />

diese Funktionalität ermöglicht. Er lautet: protected. Der folgen<strong>de</strong> Zugriff auf<br />

die private Instanzvariable intBesatzung <strong>de</strong>r Basisklasse führt zu einem<br />

Fehler:<br />

69


Durch die folgen<strong>de</strong> Modifikation <strong>de</strong>r Basisklasse wird dieser Fehler vermie<strong>de</strong>n<br />

und <strong>de</strong>r Zugriff über die Kindklasse erlaubt.<br />

Dotty: „Der Fehler ist zwar nicht mehr da, doch die genauen<br />

Zusammenhänge liegen für mich immer noch im verborgenen!“<br />

Wird ein Member mit <strong>de</strong>m Zugriffsmodifizierer protected <strong>de</strong>klariert, verhält es<br />

sich für die betroffene Klasse wie mit private <strong>de</strong>klariert. Es ist nur innerhalb <strong>de</strong>r<br />

Klasse sichtbar. Der Unterschied kommt beim Vererben zum tragen. Das<br />

vererbte protected Member ist in <strong>de</strong>r Kindklasse sichtbar und es kann darauf<br />

zugegriffen wer<strong>de</strong>n.<br />

70


Konstruktoren im Kontext <strong>de</strong>r Vererbung<br />

Besitzt eine Basisklasse einen o<strong>de</strong>r mehrere Konstruktoren, stellt sich uns die<br />

Frage, ob diese beim Vererbungsvorgang in die Kindklasse übernommen<br />

wer<strong>de</strong>n. Die Antwort lautet: Nein. Eine Basisklasse besitzt keine Informationen<br />

über die Member <strong>de</strong>r Kindklasse, was be<strong>de</strong>utet, dass die abgeleitete Klasse, falls<br />

notwendig, selbst für die Konstruktoren verantwortlich ist.<br />

Welcher Konstruktor wird wann aufgerufen?<br />

Besitzen sowohl die Basis- als auch die Kindklasse explizit <strong>de</strong>finierte<br />

Konstruktoren, fragen wir uns: „Wann wird welcher Konstruktor aufgerufen?“<br />

Schauen Sie sich das folgen<strong>de</strong>, ausschließlich mit Konstruktoren versehene<br />

Beispiel an:<br />

71


Die Konsolen-Ausgabe lautet:<br />

Konstruktoraufruf: Basisklasse ’Raumschiff’<br />

Konstruktoraufruf: Kindklasse ’Kampfschiff’<br />

Sie sehen, dass bei <strong>de</strong>r Objektgenerierung einer abgeleiteten Klasse in Zeile 33<br />

zuerst <strong>de</strong>r parameterlose Standardkonstruktor <strong>de</strong>r Basisklasse und danach <strong>de</strong>r,<br />

<strong>de</strong>r Kindklasse aufgerufen wird. Das ist eigentlich logisch, <strong>de</strong>nn die Basisklasse<br />

ist ebenso für ihren Teil <strong>de</strong>r Initialisierung verantwortlich, wie die Kindklasse.<br />

72


Der Aufruf <strong>de</strong>r Konstruktoren in <strong>de</strong>r Vererbungshierarchie beginnt stets bei <strong>de</strong>r<br />

Wurzel, also <strong>de</strong>r Basisklasse und erfolgt von dort aus weiter entlang <strong>de</strong>r<br />

Erblinie, bis hin zum jüngsten Spross. Aus Platzgrün<strong>de</strong>n habe ich mich in<br />

meinen Beispielen auf eine einzige Kindklasse beschränkt. Sie können jedoch<br />

die Kindklasse als neue Basisklasse für eine weitere Vererbung nutzen.<br />

Member ver<strong>de</strong>cken<br />

Wir haben schon gesehen, dass durch <strong>de</strong>n Vorgang <strong>de</strong>r Vererbung, alle Member<br />

<strong>de</strong>r Basisklasse (nicht die Konstruktoren und Destruktoren), die nicht mit<br />

private <strong>de</strong>klariert wur<strong>de</strong>n, ebenso in <strong>de</strong>r Kindklasse zur Verfügung stehen. Was<br />

passiert aber, wenn z.B. eine Metho<strong>de</strong> in <strong>de</strong>r Kindklasse <strong>de</strong>n gleichen Namen<br />

inklusive Parameterliste trägt, wie eine in ihrer Basisklasse?<br />

73


Sowohl in <strong>de</strong>r Basisklasse als auch in <strong>de</strong>r Kindklasse existiert eine Metho<strong>de</strong> mit<br />

Namen getID(). Starten Sie das Programm, so lautet die Konsolen-Ausgabe:<br />

ID: Kampfschiff.<br />

Die Metho<strong>de</strong> <strong>de</strong>r Basisklasse ist überschrieben wor<strong>de</strong>n. Die Frage, die Sie sich<br />

jetzt stellen sollten ist: „Ist das von mir so gewollt, o<strong>de</strong>r habe ich durch eine<br />

Unachtsamkeit <strong>de</strong>n gleichen Namen gewählt?“ Der Compiler erkennt dies und<br />

weist Sie mit einer Warnung auf diesen Umstand hin. Sehen Sie die<br />

Schlangenlinien unterhalb von getID() innerhalb <strong>de</strong>r Kindklasse? Der<br />

Hinweis besagt, dass <strong>de</strong>r vererbte Member getID() <strong>de</strong>r Basisklasse<br />

ausgeblen<strong>de</strong>t wird. Falls das so von Ihnen gewünscht ist, können Sie die<br />

74


Warnung dadurch verhin<strong>de</strong>rn, dass das Schlüsselwort new in <strong>de</strong>r Kindklasse<br />

verwen<strong>de</strong>t wird:<br />

Dotty: „Können wir jetzt nicht mehr auf die ver<strong>de</strong>ckte Metho<strong>de</strong> zugreifen?“<br />

Doch, das ich weiterhin möglich. Durch die Verwendung <strong>de</strong>s Schlüsselwortes<br />

base wird <strong>de</strong>r Zugriff auf die Basisklasse ermöglicht.<br />

75


Die Konsolen-Ausgabe lautet:<br />

ID: Raumschiff.<br />

Polymorphie<br />

Kommen wir jetzt zu einem Punkt, <strong>de</strong>r vielleicht ein paar Stirnrunzeln bei Ihnen<br />

hervorrufen wird. Übersetzt be<strong>de</strong>utet Polymorphie Vielgestaltigkeit. In <strong>C#</strong><br />

können in einer Basisklasse z.B. Metho<strong>de</strong>n existieren, die in <strong>de</strong>r abgeleiteten<br />

Kindklasse neu <strong>de</strong>finiert wer<strong>de</strong>n. Dadurch erlangen wir die Fähigkeit,<br />

76


estehen<strong>de</strong>n Programm-Co<strong>de</strong> ohne Anpassung bzw. Modifikation nutzen zu<br />

können, ihn jedoch nach unseren Bedürfnissen zu erweitern. Vererbung ist also<br />

ein zwingen<strong>de</strong>r Bestandteil für Polymorphie. Doch es gehört noch ein wenig<br />

mehr dazu.<br />

Dotty: „Haben wir Polymorphie nicht schon längst in unserem letzten<br />

Beispiel mit <strong>de</strong>r neu <strong>de</strong>finierten Metho<strong>de</strong> erreicht? Die neue Metho<strong>de</strong> in <strong>de</strong>r<br />

Kindklasse hat die bestehen<strong>de</strong> <strong>de</strong>r Basisklasse mit neuer Funktionalität<br />

abgelöst.“<br />

Das ist eben nicht <strong>de</strong>r Fall. Schauen wir uns das nun folgen<strong>de</strong> Beispiel an,<br />

welches nichts mit Polymorphie zu tun hat.<br />

Die Basisklasse Raumschiff dient als Ausgangspunkt für unsere geplanten<br />

Weiterentwicklungen Kampfschiff und Transportschiff.<br />

77


Die Kindklasse Kampfschiff wird von <strong>de</strong>r Basisklasse Raumschiff abgeleitet.<br />

Die Kindklasse Transportschiff wird von <strong>de</strong>r Basisklasse Raumschiff abgeleitet.<br />

78


Im Hauptprogramm legen wir ein Array mit drei Elementen an, welches die<br />

Raumschiff-Objekte aufnehmen kann (Zeile 58).<br />

Dotty: „Jetzt bin ich vollends verwirrt! Wir erzeugen Referenzen vom Typ<br />

Raumschiff, die aber auf unterschiedliche Objekte (Kampfschiff bzw.<br />

Transportschiff) zeigen. Wie soll das <strong>de</strong>nn gehen?“<br />

Wir halten fest, dass ein Kampfschiff bzw. ein Transportschiff immer auch ein<br />

Raumschiff ist. Das wird in <strong>de</strong>r OOP eine ist-ein-Beziehung genannt. Deshalb<br />

kann die Referenzvariable Raumschiff sowohl auf ein Kampfschiff, als auch auf<br />

ein Transportschiff weisen. Natürlich hat die Basisklasse keine Kenntnis von<br />

<strong>de</strong>n Membern <strong>de</strong>r Kindklasse(n) und kann aus diesem Grun<strong>de</strong> nicht auf sie<br />

zugreifen. Doch schauen wir uns die Konsolen-Ausgabe einmal genauer an:<br />

ID: Raumschiff. Fighter<br />

ID: Raumschiff. Transporter<br />

ID: Raumschiff. Raumschiff<br />

Was erkennen wir? Nun, die ID-Kennung lautet in je<strong>de</strong>m Fall für alle drei<br />

Raumschiffe Raumschiff. Ist das korrekt? Gemäß Programm-Co<strong>de</strong> zwar eine<br />

korrekte Ausgabe, doch nicht unbedingt gewollt. Es wird stets die Basisklassen-<br />

Implementierung <strong>de</strong>r Metho<strong>de</strong> getID() aufgerufen und nicht die<br />

79


entsprechen<strong>de</strong> in <strong>de</strong>r Kindklasse. Dieses Verhalten kommt <strong>de</strong>swegen zustan<strong>de</strong>,<br />

weil wir es mit einer statischen Bindung (early-binding) zu tun haben. Es steht<br />

zur Entwicklungszeit schon fest, welche Metho<strong>de</strong> an welches Objekt gebun<strong>de</strong>n<br />

ist. Doch wie erreichen wir <strong>de</strong>n korrekten Aufruf <strong>de</strong>r Kindklassen-Metho<strong>de</strong><br />

getID()?<br />

virtual und overri<strong>de</strong><br />

Die bei<strong>de</strong>n Schlüsselwörter virtual und overri<strong>de</strong> helfen unserem Programm-<br />

Co<strong>de</strong> auf die Beine. Sie bewirken, dass wir über eine Basisklassenreferenz auf<br />

eine Metho<strong>de</strong> in <strong>de</strong>r abgeleiteten Kindklasse Zugriff nehmen können. Dies wird<br />

dynamische o<strong>de</strong>r späte Bindung (late-binding) genannt. Die Metho<strong>de</strong>nbindung<br />

an ein Objekt steht erst zur Laufzeit <strong>de</strong>s Programms zur Verfügung. Damit wir<br />

wahre Polymorphie erleben, müssen zwei Modifikationen vorgenommen<br />

wer<strong>de</strong>n:<br />

1. Die Basisklassen<strong>de</strong>finition muss mit <strong>de</strong>m Schlüsselwort virtual versehen<br />

wer<strong>de</strong>n<br />

2. Die Kindklassen<strong>de</strong>finition muss mit <strong>de</strong>m Schlüsselwort overri<strong>de</strong> versehen<br />

wer<strong>de</strong>n. Sie kennzeichnet das Überschreiben <strong>de</strong>r Basisklassen<strong>de</strong>finition<br />

Die Co<strong>de</strong>-Än<strong>de</strong>rungen lauten im Detail:<br />

Je<strong>de</strong> betroffene Metho<strong>de</strong> <strong>de</strong>r Kindklasse muss mit <strong>de</strong>m Schlüsselwort overri<strong>de</strong><br />

versehen wer<strong>de</strong>n<br />

80


Starten wir jetzt das Programm, erhalten wir die Konsolen-Ausgabe:<br />

ID: Kampfschiff. Fighter<br />

ID: Transportschiff. Transporter<br />

ID: Raumschiff. Raumschiff<br />

Sie sehen, dass jetzt die entsprechen<strong>de</strong>n Metho<strong>de</strong>n (ID: ...) <strong>de</strong>r Kindklassen<br />

aufgerufen wer<strong>de</strong>n. Fassen wir noch einmal die wichtigen Punkte für<br />

Polymorphie zusammen:<br />

♦ Die Basisklasse muss eine mit virtual <strong>de</strong>klarierte Metho<strong>de</strong> besitzen<br />

♦ In <strong>de</strong>r abgeleiteten Klasse wird die gleichnamige Metho<strong>de</strong> mit overri<strong>de</strong><br />

überschrieben<br />

♦ Der Aufruf erfolgt über eine Basisklassenreferenz <strong>de</strong>r Vererbungshierarchie<br />

81


Statische Klassen<br />

Sie haben sich sicherlich schon oft gefragt, warum die Metho<strong>de</strong> Main() mit <strong>de</strong>m<br />

Schlüsselwort static <strong>de</strong>finiert wur<strong>de</strong>. Eingangs habe ich kurz erwähnt, dass es<br />

nicht notwendig ist, für die Startmetho<strong>de</strong> Main() eine Instanz zu generieren. Es<br />

muss zu Beginn eines Programms einen initialen Mechanismus geben, von <strong>de</strong>m<br />

aus alle weiteren Aktionen ausgehen. Am Anfang haben wir ja noch kein<br />

einziges Objekt und Main wird als Einsprungpunkt genutzt. Sind wir erst<br />

einmal in Main angekommen, können natürlich Objekte generiert wer<strong>de</strong>n. Es<br />

gibt jedoch Anfor<strong>de</strong>rungen, die nicht notwendigerweise ein Objekt<br />

voraussetzten. Ein Beispiel hierfür ist die Klasse Math.<br />

Sie sehen in Zeile 18 <strong>de</strong>n Aufruf <strong>de</strong>r Metho<strong>de</strong> Sqrt (Square-Root = Quadrat-<br />

Wurzel) <strong>de</strong>r Klasse Math. Es war <strong>de</strong>mnach nicht notwendig zuvor eine Instanz<br />

<strong>de</strong>r Klasse Math zu bil<strong>de</strong>n, um die Metho<strong>de</strong> Sqrt nutzen zu können. Zu<strong>de</strong>m<br />

wur<strong>de</strong>n keine Instanzvariablen zur Berechnung benötigt und es existieren auch<br />

keine Metho<strong>de</strong>n, die über gemeinsame Instanzvariablen möglicherweise Daten<br />

austauschen. Warum also ein Objekt erschaffen, wenn nur die Metho<strong>de</strong>n zu<br />

nutzen sind? Schauen Sie sich das folgen<strong>de</strong> Beispiel an, dass eine statische<br />

Metho<strong>de</strong> innerhalb <strong>de</strong>r Klasse <strong>de</strong>finiert, in <strong>de</strong>r sich auch Main befin<strong>de</strong>t.<br />

82


Eleganter ist es natürlich, wenn Sie sich eine eigene Klasse schreiben, die alle<br />

für Sie wichtigen Metho<strong>de</strong>n zur Berechnung enthält. Das ist ungleich schwerer.<br />

Hier sehen Sie <strong>de</strong>n Co<strong>de</strong> für die Klassen<strong>de</strong>finition:<br />

83


Achten Sie darauf, dass Sie <strong>de</strong>n Zugriffsmodifizierer public nicht vergessen.<br />

An<strong>de</strong>rnfalls wird die Metho<strong>de</strong> implizit als private <strong>de</strong>klariert und Sie können sie<br />

nicht aufrufen. Der Aufruf <strong>de</strong>r Metho<strong>de</strong> ist nicht weiter schwierig. Sie müssen<br />

nur <strong>de</strong>n Klassennamen <strong>de</strong>m Metho<strong>de</strong>naufruf voransetzten.<br />

84


Konstruktoren<br />

Dotty: „So wie ich die Sache sehe, benötigen wir zu Nutzung <strong>de</strong>r statischen<br />

Klassenelemente kein Objekt. Gibt es <strong>de</strong>nn überhaupt Konstruktoren? Diese<br />

wer<strong>de</strong>n eigentlich durch das Schlüsselwort new aufgerufen, was aber in<br />

diesem Fall nicht möglich ist.“<br />

Wir können auch hier einen Konstruktor verwen<strong>de</strong>n. Dieser wird dann<br />

aufgerufen, bevor die erste statische Metho<strong>de</strong> aufgerufen wird o<strong>de</strong>r eine Instanz<br />

erstellt wur<strong>de</strong>.<br />

85


Die Zeile 14 ruft erstmalig die statische Metho<strong>de</strong> Mathe.Add() auf, was einen<br />

vorherigen Aufruf <strong>de</strong>s Konstruktors be<strong>de</strong>utet. Die Konsolen-Ausgabe lautet:<br />

Konstruktoraufruf.<br />

7<br />

54<br />

Be<strong>de</strong>nken Sie, dass es sich in diesem Fall um eine Klassen-Metho<strong>de</strong> han<strong>de</strong>lt,<br />

wogegen eine Metho<strong>de</strong> eines real existieren<strong>de</strong>n Objektes Objekt-Metho<strong>de</strong><br />

genannt wird.<br />

Eine Klasse kann sowohl Objekt-Metho<strong>de</strong>n als auch Klassen-Metho<strong>de</strong>n<br />

beinhalten. Sie sollten jedoch wissen, dass Klassen-Metho<strong>de</strong>n ausschließlich auf<br />

statische Klassenelemente (statische Variablen bzw. Klassen-Metho<strong>de</strong>n)<br />

zugreifen können. Das folgen<strong>de</strong> Beispiel einer Klassen<strong>de</strong>finition zeigt das<br />

Problem, dass die Klassen-Metho<strong>de</strong> getWert() auf eine Objekt-Variable<br />

zugreifen möchte. Der Zugriff ist jedoch nur über eine Objekt-Referenz<br />

(Verweis) möglich.<br />

Die Fehlermeldung lautet:<br />

86


Um dieses Zwitterverhalten von Klassen-Elementen und Objekt-Elementen zu<br />

vermei<strong>de</strong>n, ist es möglich, eine Klasse komplett statisch zu <strong>de</strong>klarieren. Das hat<br />

zur Folge, dass alle Klassen-Elemente ebenfalls statisch sein müssen. Erkennen<br />

Sie, was das wie<strong>de</strong>rum zur Folge hat? Es kann niemals eine einzige Instanz<br />

dieser Klasse erstellt wer<strong>de</strong>n.<br />

Dotty: „Ich sehe eigentlich keinen einzigen Grund, warum ich z.B. eine<br />

statische Klassen-Variable und eine Objekt-Metho<strong>de</strong> <strong>de</strong>klarieren sollte.“<br />

Stellen wir uns vor, dass wir eine Klasse erstellt haben, von <strong>de</strong>r mehrere Objekt-<br />

Instanzen erstellt wer<strong>de</strong>n müssen. Sie wollen aber die Übersicht behalten, wie<br />

viele Objekt-Instanzen erstellt wur<strong>de</strong>n. Es ist also ein Zähler von Nöten, <strong>de</strong>r die<br />

einzelnen generierten Instanzen aufaddiert. Wür<strong>de</strong>n wir eine Objekt-Variable<br />

innerhalb einer Klasse <strong>de</strong>klarieren, bekämen wir bei je<strong>de</strong>r neuen<br />

Objektinstanziierung eine neue unabhängige Variable. Aus diesem Grund<br />

nutzen wir eine Klassen-Variable, die mit static <strong>de</strong>klariert wur<strong>de</strong>. Sie ist Objekt<br />

unabhängig und nur <strong>de</strong>r Klasse verpflichtet und wird durch <strong>de</strong>n Konstruktor <strong>de</strong>r<br />

Klasse bei je<strong>de</strong>r Instanziierung (Zeile 14, 15 und 16) inkrementiert.<br />

87


Die Konsolen-Ausgabe lautet:<br />

Anzahl <strong>de</strong>r Instanzen: 3<br />

Lassen Sie uns die gewonnen Erkenntnisse zusammenfassen:<br />

♦ Der Zugriff auf statische Metho<strong>de</strong>n und Variablen erfolgt über <strong>de</strong>n<br />

Klassennamen. Das folgen<strong>de</strong> Beispiel zeigt <strong>de</strong>n Zugriff auf die Klassen-<br />

88


Metho<strong>de</strong> Add()<br />

♦ Statische Metho<strong>de</strong>n können nur auf statische Variablen bzw. statische<br />

Metho<strong>de</strong>n zugreifen. Auf Instanz-Variablen bzw. Instanz-Metho<strong>de</strong>n können<br />

sie nicht zugreifen. Dafür wäre eine Objekt-Referenz bzw. ein Verweis<br />

notwendig.<br />

♦ Statische Konstruktoren wer<strong>de</strong>n vor <strong>de</strong>m ersten Aufruf einer statischen<br />

Metho<strong>de</strong> o<strong>de</strong>r durch Instanziierung aufgerufen. Statische Konstruktoren<br />

erlauben keine Parameter bzw. Zugriffsmodifizierer.<br />

Globale Variablen<br />

Wir können mit statischen Klassen z.B. globale Variablen simulieren, die es in<br />

<strong>C#</strong> eigentlich gar nicht gibt. Fügen Sie einfach eine neue Klasse Ihrem Projekt<br />

hinzu und <strong>de</strong>klarieren die Variable(n) darin als statisch. Gehen Sie wie folgt<br />

vor, um eine neue Klasse <strong>de</strong>m aktuellen Projekt hinzuzufügen:<br />

89


1. Aktuelles Projekt markieren + rechte Maustaste<br />

2. Hinzufügen...<br />

3. Neues Element<br />

Im nachfolgen<strong>de</strong>n Dialog<br />

90


4. Die Klassenvorlage wählen<br />

5. Einen ein<strong>de</strong>utigen Namen vergeben<br />

6. Den Hinzufügen-Button klicken<br />

Im Projektmappen-Explorer erscheint jetzt die neue Klasse:<br />

91


Wechseln Sie mit einem Doppelklick auf <strong>de</strong>n Eintrag in die Co<strong>de</strong>-View <strong>de</strong>r<br />

Klasse und geben als Beispiel folgen<strong>de</strong>s ein:<br />

Anschließend können Sie in Ihrem Hauptprogramm auf die Klassenvariablen<br />

zugreifen, in<strong>de</strong>m Sie <strong>de</strong>n Klassennamen plus Variablennamen verwen<strong>de</strong>n.<br />

IntelliSense bietet die öffentlichen Variablen <strong>de</strong>r Klasse variables zur Auswahl<br />

an. Sie können an je<strong>de</strong>r Stelle Ihres Programms auf diese Art und Weise<br />

schreibend o<strong>de</strong>r lesend zugreifen.<br />

Main-Parameter<br />

Vielleicht haben sich einige von Ihnen die Metho<strong>de</strong> Main() ein wenig genauer<br />

angeschaut und sich gewun<strong>de</strong>rt, warum innerhalb <strong>de</strong>s run<strong>de</strong>n Klammernpaares<br />

etwas steht. Es sieht so aus, als ob wir <strong>de</strong>r Metho<strong>de</strong> etwas beim Start <strong>de</strong>r<br />

Anwendung übergeben könnten. Der Datentyp ist string und es han<strong>de</strong>lt sich um<br />

92


ein Array, was wir an <strong>de</strong>n eckigen Klammern erkennen. Der Variablenname<br />

args ist in diesem Fall willkürlich gewählt und be<strong>de</strong>utet soviel wie Argumente.<br />

Sicherlich haben Sie schon einmal das Programm copy bzw. xcopy innerhalb<br />

<strong>de</strong>r DOS-Box verwen<strong>de</strong>t. Diese nützlichen Tools kopieren Dateien bzw.<br />

Verzeichnisse von einem Speicherort zum an<strong>de</strong>ren. Damit sie ihre Arbeit<br />

erfolgreich ausführen können, sind mehrere zusätzliche Angaben erfor<strong>de</strong>rlich.<br />

Was möchten Sie wohin kopieren. Nehmen wir z.B. copy. Sie müssen als erstes<br />

Argument angeben, was sie kopieren möchten und als zweites wohin. Also<br />

vielleicht:<br />

copy c:\test.txt d:\info<br />

Diese Befehlszeile kopiert die Datei test.txt <strong>de</strong>r Partition c:\ in das Verzeichnis<br />

info <strong>de</strong>r Partition d:\.<br />

Dotty: „Wie können wir aber aus <strong>de</strong>r Entwicklungsumgebung heraus <strong>de</strong>r<br />

Anwendung einige Argumente übergeben?“<br />

Ganz einfach! Im Projektmappen-Explorer klicken wir auf unser Projekt und<br />

öffnen über die rechte Maustaste das Kontext-Menü und wählen dort <strong>de</strong>n<br />

Eintrag Eigenschaften. Danach wechseln wir in <strong>de</strong>n Reiter Debuggen.<br />

93


Sie erkennen auf <strong>de</strong>r rechten Seite das Textfeld Befehlszeilenargumente. Dort<br />

geben Sie die einzelnen Argumente durch Leerzeichen getrennt an. Wen<strong>de</strong>n wir<br />

uns jedoch jetzt wie<strong>de</strong>r <strong>de</strong>r Anwendung zu. Vorab habe ich folgen<strong>de</strong> Einträge<br />

vorgenommen:<br />

Sie sehen, dass es sich um 3 Argumente han<strong>de</strong>lt.<br />

94


Die Funktion <strong>de</strong>r foreach-Schleife sollte Ihnen bekannt sein. Sie durchläuft in<br />

diesem Fall alle Elemente <strong>de</strong>s Arrays args, wobei bei je<strong>de</strong>m einzelnen<br />

Durchlauf das ermittelte Element in <strong>de</strong>r Variablen strArgument abgelegt wird.<br />

In Zeile 15 erfolgt die Ausgabe auf die Konsole, die da lautet:<br />

<strong>C#</strong><br />

macht<br />

Spass!<br />

Sie können natürlich auch die alternative Möglichkeit mit einer for-Schleife<br />

programmieren.<br />

95


Zeile<br />

Erklärung<br />

14 Überprüfung, ob überhaupt Argumente übergeben wur<strong>de</strong>n. Falls nicht, wird eine<br />

Meldung auf <strong>de</strong>r Konsole ausgegeben.<br />

17, 18 Wur<strong>de</strong>n Argumente übergeben (args.Length != 0), wer<strong>de</strong>n diese über eine for-Schleife<br />

Tab. 13:<br />

an die Konsole geschickt.<br />

Co<strong>de</strong>-Erläuterungen<br />

Natürlich kann die Metho<strong>de</strong> Main() auch einen Wert zurückliefern. Ersetzen Sie<br />

einfach das Schlüsselwort void durch int.<br />

Enumerationen<br />

Sie haben kürzlich die Konstanten kennen gelernt. Es han<strong>de</strong>lte sich dabei um<br />

ein Sprachelement, welches einen Wert speichern kann und zur Laufzeit nicht<br />

verän<strong>de</strong>rt wer<strong>de</strong>n darf. Enumerationen o<strong>de</strong>r auch Aufzählungen sind ähnliche<br />

Konstrukte. Eine Enumeration gruppiert mehrere Konstante, die zu einem<br />

bestimmten Kontext gehören. Möchten Sie in Ihrem Programm z.B. die<br />

Planeten unseres Sonnensystems ansprechen, so ist es möglicherweise etwas<br />

umständlich und unübersichtlich, sie anhand ihrer Positionsnummer zu<br />

benennen. Schauen Sie sich dazu das folgen<strong>de</strong> Enumerations-Beispiel unseres<br />

Sonnensystems an und nageln Sie mich bitte nicht darauf fest, dass ich nicht<br />

alle neu hinzugekommenen Planeten, die erst kürzlich <strong>de</strong>n Aufnahmetest<br />

bestan<strong>de</strong>n haben, auch noch aufführe. Pluto scheint ja nicht mehr dazu zu<br />

gehören.<br />

96


Zeile<br />

Erklärung<br />

9 - 20 Definition <strong>de</strong>r Enumeration Sonnensystem vom Datentyp int<br />

25 Deklaration <strong>de</strong>r Variablen MeinSystem vom Typ Sonnensystem<br />

27 Initialisierung <strong>de</strong>r Variablen MeinSystem mit einem Wert aus <strong>de</strong>r Auswahlliste<br />

Tab. 14: Co<strong>de</strong>-Erläuterungen<br />

97


Die allgemeine Syntax für eine Enumeration lautet:<br />

enum Name [:] { };<br />

Wie Sie sehen, ist <strong>de</strong>r angegebene Basisdatentyp optional. Lassen Sie ihn weg,<br />

so wird standardmäßig <strong>de</strong>r Datentyp auf int gesetzt. Es können nur die<br />

ganzzahligen Datentypen byte, short, int und long verwen<strong>de</strong>t wer<strong>de</strong>n. Sie sehen<br />

in Zeile 11, dass ich <strong>de</strong>r Konstanten Merkur explizit einen Wert zugewiesen<br />

habe. Alle nachfolgen<strong>de</strong>n Konstanten, also Venus, Er<strong>de</strong>, Mars usw., benötigen<br />

eigentlich keine explizite Angabe eines Wertes, wenn dieser sich bei je<strong>de</strong>r<br />

neuen Konstanten um <strong>de</strong>n Wert 1 erhöhen soll. Dies geschieht implizit. Wir<br />

hätten also auch<br />

schreiben können. Wird bei <strong>de</strong>m ersten Element <strong>de</strong>r Aufzählung kein<br />

Initialisierungswert angeben, erhält dieses implizit <strong>de</strong>n Wert 0 zugewiesen. Es<br />

ist jedoch auch möglich, die Folge an einer beliebigen Stelle mit einem an<strong>de</strong>ren<br />

Wert fortsetzen zu lassen. Alle nachfolgen<strong>de</strong>n Elemente wer<strong>de</strong>n bezogen auf<br />

<strong>de</strong>n neuen Startwert, wie<strong>de</strong>rum jeweils um <strong>de</strong>n Wert 1 erhöht.<br />

98


Die Konstanten besitzen nach dieser Deklaration folgen<strong>de</strong> Werte:<br />

Konstante Wert Initialisierung<br />

Melmac 17 Explizit<br />

Eligor 18 Implizit<br />

Mindrap 19 Implizit<br />

Luginar 73 Explizit<br />

Lemgos 74 Implizit<br />

Eltar 75 Implizit<br />

Die Enumeration hat im IntelliSense ein eigenes Icon:<br />

Icon<br />

Erklärung<br />

Tab. 15:<br />

Signalisiert, dass es sich um eine Enumeration han<strong>de</strong>lt<br />

Signalisiert, dass es sich um ein Element (Konstante) <strong>de</strong>r Enumeration han<strong>de</strong>lt<br />

Iconerklärungen<br />

Innerhalb von .NET sind etliche Enumerationen vorhan<strong>de</strong>n, die Sie auf Schritt<br />

und Tritt verfolgen. Das folgen<strong>de</strong> Beispiel legt eine Hintergrundfarbe für die<br />

Konsole fest, wobei die einzelnen Farben in einer Enumeration abgelegt sind.<br />

99


Dotty: „Gibt es eine Möglichkeit, alle Elemente einer Enumeration mit ihren<br />

Werten auszugeben?“<br />

Elemente <strong>de</strong>r Enumeration ausgeben<br />

Sicherlich! Das folgen<strong>de</strong> Co<strong>de</strong>fragment schreibt alle Konstanten <strong>de</strong>r<br />

Enumeration Sonnensystem mit ihren Werten auf die Konsole:<br />

100


Die Konsolen-Ausgabe lautet:<br />

Element: Melmac Value: 17<br />

Element: Eligor Value: 18<br />

Element: Mindrap Value: 19<br />

Element: Luginar Value: 73<br />

Element: Lemgos Value: 74<br />

Element: Eltar Value: 75<br />

Dazu nutzen wir zwei Metho<strong>de</strong>n <strong>de</strong>r Struktur Enum, von <strong>de</strong>r die<br />

Aufzählungstypen abgeleitet wer<strong>de</strong>n.<br />

101


Metho<strong>de</strong><br />

Erklärung<br />

GetValues() Liest die Werte <strong>de</strong>r Konstanten einer<br />

Enumeration aus. Rückgabe: Array<br />

GetName()<br />

Liefert bei angegebenem Wert <strong>de</strong>n Namen <strong>de</strong>r<br />

Konstanten<br />

Tab. 16: Metho<strong>de</strong>n <strong>de</strong>r Enum-Struktur<br />

Werte <strong>de</strong>r Konstanten ausgeben<br />

Gehen wir die Sache mal im Detail durch. Die Metho<strong>de</strong> GetValues() liefert<br />

beim Aufruf ein Array mit <strong>de</strong>n einzelnen Werten <strong>de</strong>r <strong>de</strong>finierten Konstanten<br />

zurück.<br />

Die Konsolen-Ausgabe lautet:<br />

Value: 17<br />

Value: 18<br />

Value: 19<br />

Value: 73<br />

Value: 74<br />

Value: 75<br />

Sie sehen, dass alle in <strong>de</strong>r Enumeration <strong>de</strong>finierten Werte ausgegeben wer<strong>de</strong>n.<br />

Dotty: „Was be<strong>de</strong>utet das typeof(Sonnensystem)?“<br />

102


Die Metho<strong>de</strong> typeof() liefert eine Typbeschreibung eines Datentyps zurück.<br />

Diese Typbeschreibung wird in <strong>de</strong>r Metho<strong>de</strong> GetValues() als Argument<br />

übergeben.<br />

Der Tooltip von GetValues() liefert einige wichtige Hinweise über <strong>de</strong>n Typ<br />

<strong>de</strong>s Parameters und <strong>de</strong>n Rückgabetyp.<br />

Haben wir die Werte ermittelt, können wir mit Hilfe <strong>de</strong>r Metho<strong>de</strong> GetName()<br />

<strong>de</strong>n Namen <strong>de</strong>r Konstanten erfahren, die sich dahinter verbirgt. Das folgen<strong>de</strong><br />

kleine Programm fragt über die Konsole nach einem Wert und gibt<br />

anschließend <strong>de</strong>n passen<strong>de</strong>n Konstantennamen aus.<br />

Die Metho<strong>de</strong> GetName() erwartet dabei zwei Parameter. Der erste ist <strong>de</strong>r Typ<br />

<strong>de</strong>r Enumeration und <strong>de</strong>r zweite <strong>de</strong>r Konstantenwert, <strong>de</strong>r zur Ermittlung <strong>de</strong>s<br />

Namens benötigt wird.<br />

Konstantennamen ausgeben<br />

Es existiert übrigens noch eine interessante Metho<strong>de</strong> zur Ermittlung <strong>de</strong>r<br />

Konstantennamen. Wir sind bisher über die vorher ermittelten Werte zu <strong>de</strong>n<br />

103


Namen gelangt. Die Metho<strong>de</strong> GetNames() liefert ein Array mit allen<br />

Elementen <strong>de</strong>r Enumeration zurück.<br />

Die Konsolen-Ausgabe lautet:<br />

Melmac<br />

Eligor<br />

Mindrap<br />

Luginar<br />

Lemgos<br />

Eltar<br />

Dotty: “Gibt es eine Möglichkeit herauszufin<strong>de</strong>n, ob ein bestimmter Name in<br />

einer Enumeration <strong>de</strong>finiert wur<strong>de</strong>?”<br />

Das ist machbar. Die Struktur Enum bietet dazu eine Metho<strong>de</strong> mit Namen<br />

IsDefined() an. Beachten Sie, dass bei <strong>de</strong>r Übergabe <strong>de</strong>s Namens an die<br />

Metho<strong>de</strong> die Schreibweise (Case-Sensitive) eine Rolle spielt.<br />

104


Der vorliegen<strong>de</strong> Co<strong>de</strong> überprüft das Vorhan<strong>de</strong>nsein <strong>de</strong>s Elements Lemgos in <strong>de</strong>r<br />

Enumeration Sonnensystem.<br />

Basisdatentyp zur Laufzeit ermitteln<br />

Dotty: „Können wir mit Hilfe einer Metho<strong>de</strong> <strong>de</strong>n Basisdatentyp einer<br />

Enumeration zur Laufzeit ermitteln?“<br />

Das ist mit <strong>de</strong>r Metho<strong>de</strong> GetUn<strong>de</strong>rlyingType() möglich.<br />

Die Konsolen-Ausgabe für unser Beispiel lautet:<br />

System.Int32<br />

Das ist <strong>de</strong>r .NET-Laufzeittyp für <strong>de</strong>n Datentyp int, <strong>de</strong>r implizit für unsere<br />

Enumeration vergeben wur<strong>de</strong>. Doch schauen wir uns zum Schluss noch ein<br />

kurzes Anwendungsbeispiel an, wobei eine Metho<strong>de</strong> genutzt wird, <strong>de</strong>r wir ein<br />

Argument übergeben. Das erwartete Argument ist eine Enumeration, so dass<br />

sich die Auswahl über IntelliSense als sehr hilfreich und viel sagend erweist. Es<br />

ist auf je<strong>de</strong>n Fall für einen Menschen einleuchten<strong>de</strong>r bzw. verständlicher, eine<br />

für sich sprechen<strong>de</strong> Enumeration anzugeben, als irgen<strong>de</strong>inen nichts sagen<strong>de</strong>n<br />

Zahlenwert. Für das folgen<strong>de</strong> Beispiel lege ich wie<strong>de</strong>r die eingangs vorgestellte<br />

Enumeration über unser Sonnensystem zugrun<strong>de</strong>. Die Metho<strong>de</strong> gestaltet sich<br />

folgen<strong>de</strong>rmaßen:<br />

105


Sie sehen, dass <strong>de</strong>r Parameter s vom Datentyp Sonnensystem ist. Dieser wird in<br />

einer case-Anweisung auf <strong>de</strong>n Inhalt überprüft und entsprechend verzweigt. Der<br />

Einfachheit halber habe ich nur zwei Möglichkeiten zur Auswahl angeboten,<br />

doch Sie sehen sicherlich sofort, worum es geht. Der Aufruf <strong>de</strong>r Metho<strong>de</strong> lautet<br />

dann:<br />

Ist doch fantastisch! IntelliSense bietet uns die zur Verfügung stehen<strong>de</strong>n<br />

Konstanten zur Auswahl an. Da gehören Tippfehler <strong>de</strong>r Vergangenheit an und<br />

Sie können sich sofort etwas unter <strong>de</strong>n für sich sprechen<strong>de</strong>n Konstanten<br />

vorstellen.<br />

106


Dotty: „Die Auswahl <strong>de</strong>r Konstanten in <strong>de</strong>r Enumeration entspricht in <strong>de</strong>r<br />

Reihenfolge aber nicht <strong>de</strong>r in <strong>de</strong>r Deklaration. Wie kommt das?“<br />

Verantwortlich dafür ist die Entwicklungsumgebung, die die Einträge<br />

alphabetisch sortiert. Das soll uns aber nicht weiter beunruhigen.<br />

107

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!