C# von Kopf bis Fuß

2.740 Aufrufe

Veröffentlicht am

Dieses Standardwerk aus der beliebten „von Kopf bis Fuß“-Reihe nimmt den Leser auf eine Erlebnistour durch C#, bei der sowohl seine beiden Gehirnhälften als auch seine Lachmuskeln stimuliert werden. C# von Kopf bis Fuß ist ein unterhaltsames und visuell ansprechendes Arbeitsbuch für die objektorientierte Programmierung mit C# und der Visual Studio IDE.

In der 3. Auflage deckt es C# 5 und das .NET Framework 4.5 ab. Behandelt werden alle zentralen Themen, von den Sprachgrundlagen bis zur Garbage Collection, den Erweiterungsmethoden und Animationen mit Double-Buffering. Der Leser lernt außerdem, wie er die Syntax von C# und die Abfrage von Datenquellen mit LINQ meistert. Neu aufgenommen wurden zwei Kapitel zur App-Programmierung; u.a. wird exemplarisch eine Windows Phone App entwickelt. Wer dieses Buch durchgearbeitet hat, ist ein kompetenter C#-Programmierer, der umfangreiche Anwendungen entwerfen und programmieren kann.

http://www.oreilly.de/catalog/hfcsharp3ger/

Veröffentlicht in: Bildung
0 Kommentare
1 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

Keine Downloads
Aufrufe
Aufrufe insgesamt
2.740
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
580
Aktionen
Geteilt
0
Downloads
24
Kommentare
0
Gefällt mir
1
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

C# von Kopf bis Fuß

  1. 1. Der Inhalt vii Der Inhalt (im Überblick) Der Inhalt (jetzt ausführlich) Ihr Gehirn und C#. Sie versuchen,etwas zu lernen,und Ihr Hirn tut sein Bestes,damit das Gelernte nicht hängen bleibt.Es denkt nämlich:»Wir sollten lieber ordentlich Platz für wichtigere Dinge lassen,z. B.für das Wissen darüber,welche Tiere einem gefährlich werden könnten oder dass es eine ganz schlechte Idee ist,nackt Snowboard zu fahren.« Tja,wie schaffen wir es nun,Ihr Gehirn davon zu überzeugen,dass Ihr Leben davon abhängt,etwas über C# zu wissen? Einführung Für wen ist dieses Buch? xxx Wir wissen, was Ihr Gehirn denkt xxxi Metakognition xxxiii Machen Sie sich Ihr Hirn untertan xxxv Was Sie für dieses Buch brauchen xxxvi Lies mich xxxvii Die Fachgutachter xxxviii Danksagungen xxxix Einführung xxix 1 Erste Schritte mit C#: Apps im Handumdrehn 1 2 Es ist alles bloß Code: Unter der Motorhaube 53 3 Objekte: Orientieren Sie sich!: Aufgabenspezifischer Code 101 4 Typen und Referenzen: Es ist 10:00. Wissen Sie, wo Ihre Daten sind? 141 C# Workshop 1: Ein Tag beim Rennen 187 5 Kapselung: Alles zu zeigen, ist nicht immer richtig 197 6 Vererbung: Der Stammbaum Ihres Objekts 237 7 Schnittstellen und abstrakte Klassen: Klassen, die Versprechen halten 293 8 Enums und Auflistungen: Daten in Massen speichern 351 9 Dateien lesen und schreiben: Speichere das Array, rette die Welt 409 C# Workshop 2: Die Suche 465 10 Windows Store-Apps mit XAML: Ihre Apps auf die nächste Stufe bringen 487 11 XAML, Datei-I/O und Datenkontraktserialisierung: Entschuldigen Sie die Unterbrechung 535 12 Exception-Handling: Fehler-Prävention 569 13 Captain Amazing: Der Tod des Objekts 611 14 Datenabfrage und App-Bau mit LINQ: Bekommen Sie Ihre Daten in den Griff 649 15 Events und Delegates: Was Ihr Code macht, wenn Sie nicht gucken 701 16 App-Entwurf mit dem MVVM-Muster: Tolle Apps, außen wie innen 745 C# Workshop 3: Invaders 807 17 Bonusprojekt: Erstellen Sie eine Windows Phone-App 831 A Was übrig bleibt: Die Top 11 der Themen, die es nicht ins Buch geschafft haben 845 Index 877
  2. 2. Hier fängt ein neues Kapitel an  141 Diese Daten holt gleich die Müllabfuhr! Typen und Referenzen4 Es ist 10:00. Wissen Sie, wo Ihre Daten sind? Datentyp, Datenbank, Lieutenant Commander Data … all das ist wichtiges Zeug. Ohne Daten sind Ihre Programme nutzlos. Sie brauchen Informationen von Ihren Anwendern und nutzen diese, um andere Informationen nachzuschlagen oder neue Informationen zu produzieren, die Sie dann wieder an Ihre User zurückliefern. Eigentlich schließt fast alles, was Sie beim Programmieren tun, auf die eine oder andere Weise Arbeit mit Da- ten ein. In diesem Kapitel werden Sie alles über die Datentypen von C# lernen, erfahren, wie Sie in Ihrem Programm mit Daten arbeiten, und Sie werden sogar auf einige schmutzige Geheimnisse bei Objekten stoßen (psst … auch Objekte sind Daten).
  3. 3. 142  Kapitel 4 Der Typ einer Variablen bestimmt, welche Art Daten sie speichern kann In C# sind jede Menge Typen eingebaut, die jeweils Daten unterschiedlicher Art speichern. Einige der am weitesten verbreiteten haben Sie bereits gesehen, und Sie wissen, wie man sie verwendet. Aber es gibt noch ein paar, die Ihnen bisher nicht begegnet sind, die aber ebenfalls ziemlich praktisch sein können. Typen, die Sie permanent verwenden Es sollte Sie nicht überraschen, dass int, string, bool und float die gebräuchlichsten Typen sind. ≥≥ int kann ganze Zahlen von –2.147.483.648 bis 2.147.483.647 speichern. ≥≥ string kann Text beliebiger Länge (einschließlich des leeren Strings ) speichern. ≥≥ bool ist ein Boolescher Wert – er ist entweder true oder false. ≥≥ double kann eine reelle Zahl von ±5,0 × 10−324 bis ±1,7 × 10308 mit bis zu 16 signifikanten Stellen speichern. Dieser Bereich scheint seltsam und kompliziert, ist eigentlich aber ziemlich einfach. »Signifikante Stellen« bezieht sich auf die Genauigkeit der Zahl: 35.048.410.000.000, 1.743.059, 14,43857 und 0,00004374155 haben jeweils 7 signifikante Stellen. 10308 bedeutet, dass Sie Zahlen bis zu einer Größe von 10308 (oder 1 gefolgt von 308 Nullen) speichern können – solange sie 16 oder weniger signifikante Stellen haben. Auf der anderen Seite des Wertebereichs bedeutet 10–324 , dass Sie eine Zahl so klein wie 10–324 (oder einen Dezimaltrenner gefolgt von 324 Nullen gefolgt von 1) speichern können … aber nur, wie Sie sicher schon erraten haben, solange sie 16 oder weniger signifikante Stellen hat. ≥≥ byte speichert ganze Zahlen zwischen 0 und 255. ≥≥ sbyte speichert ganze Zahlen von –128 bis 127. ≥≥ short speichert ganze Zahlen von –32.768 bis 32.767. ≥≥ ushort speichert ganze Zahlen von 0 bis 65.535. ≥≥ uint speichert ganze Zahlen von 0 bis 4.294.967.295. ≥≥ long kann jede ganze Zahl zwischen minus und plus 9 Milliarden Milliarden speichern. ≥≥ ulong kann jede ganze Zahl zwischen 0 und 18 Milliarden Milliarden speichern. Diese Typen nutzen Sie oft, wenn Sie ein Problem lösen, bei dem das »Überschlagen«, das Ihnen in ein paar Minuten begegnen wird, wirklich nützlich ist. Das »u« steht für »unsigned« (vorzeichenlos). Nicht mein Typ Eine ganze Zahl hat keinen Nachkommateil. Weitere Typen für ganze Zahlen Es gab einmal eine Zeit, in der Computerspeicher verdammt teuer und Computerprozes- soren verdammt langsam waren. Und, glauben Sie es oder nicht, wenn man den falschen Datentyp verwendete, konnte das ein Programm ernstlich ausbremsen. Glücklicherweise haben die Zeiten sich geändert, und wenn man eine ganze Zahl speichern muss, kann man meist sorglos einen int verwenden. Manchmal aber brauchen Sie etwas Größeres … und gelegentlich auch mal etwas Kleineres. Deswegen gibt Ihnen C# weitere Optionen: Das »s« in sbyte steht für »signed« (mit Vorzeichen), d. h., der Wert kann negativ sein (das Vorzeichen ist das Minuszeichen). Alle Projekte in diesem Kapitel sind Windows Forms-Anwen- dungen. Wenn wir Ihnen in diesem Kapitel sagen, dass Sie ein neues Projekt erstel- len sollen, den Projekttyp aber nicht angeben, können Sie davon ausgehen, dass es sich um eine Windows Forms- Anwendung handelt, die mit Visual Studio für Windows Desktop erstellt wird. Derartige Zahlen bezeichnet man als »Gleitkommazah- len« ... im Gegen- satz zu »Fest- kommazahlen«, die immer die gleiche Anzahl von Nach- kommastellen haben.
  4. 4. Sie sind hier 4  143 Typen und Referenzen Als Sie die Value-Eigenschaft des NumericUpDown-Steuer­ elements verwendeten, haben Sie einen decimal eingesetzt. Mit dem Windows-Rechner können Sie zwischen dezimalen Zahlen (zur Basis 10) und binären Zahlen (Zah- len zur Basis 2, die nur mit 0 und 1 geschrieben werden) wechseln – gehen Sie in den Wissenschaftlich- Modus, geben Sie eine Zahl ein und klicken Sie auf Bin, um die Zahl nach binär zu konvertieren. Klicken Sie dann auf Dec, um die Konvertierung rückgängig zu machen. Geben Sie jetzt einige der Ober- und Unter- grenzen für die ganzzahligen Typen (wie –32.768 und 255) ein und wandeln Sie sie in binär um. Haben Sie eine Idee, warum C# gerade diese Grenzen wählt? Typen zum Speichern echt riesiger und echt winziger Zahlen Manchmal sind 16 signifikante Stellen (und ein Wertebereich für astronomisch große oder subatomar kleine Zahlen) etwas übertrieben, und manchmal sind es einfach nicht genug. Deswegen stellt Ihnen C# weitere Typen zur Verfügung: ≥≥ float speichert Zahlen von ±1,5 × 10–45 bis ±3,4 × 1038 mit 7 signifikanten Stellen. ≥≥ double speichert Zahlen von ±5.0 × 10–324 bis ±1.7 × 10308 mit 15 bis16 signifikanten Stellen. ≥≥ decimal speichert Zahlen von ±1,0 × 10–28 bis ±7,9 × 1028 mit 28 bis 29 signifikanten Stellen. Auch Literale haben Typen Geben Sie in ein C#-Programm direkt eine Zahl ein, nutzen Sie ein Literal … und jedem Literal wird automatisch ein Typ zugewiesen. Das können Sie selbst sehen – geben Sie einfach folgende Zeile ein, um einer int-Variablen den Wert 14.7 zuzuweisen: int meinInt = 14.7; Versuchen Sie, das Programm zu erstellen, erscheint dies: Den gleichen Fehler erhalten Sie, wenn Sie versuchen, eine int-Variable auf eine double-Variable zu setzen. Die IDE sagt Ihnen damit, dass das Literal 14.7 einen Typ hat – und der ist double. Sie können den Typ in float ändern, indem Sie ans Ende ein F anhängen (14.7F). Und 14.7M ist ein decimal. Versuchen Sie, einer float- oder einer decimal-Variablen einfach so ein Literal zu- zuweisen, liefert Ihnen die IDE eine hilfreiche Meldung, die Sie daran erinnert, das richtige Suffix hinzuzufügen. Cool! Ein paar weitere nützliche eingebaute Typen Gelegentlich muss man einzelne Zeichen wie Q, 7 oder $ speichern. Dazu nutzt man den Typ char. Literale Werte für char stehen immer in einfachen Anführungszei- chen ('x', '3'). In die Anführungszeichen können Sie auch Escape-Sequenzen einschließen ('n' ist ein Zeilenumbruch, 't' ein Tabulator). Sie schreiben Escape- Sequenzen in Ihrem C#-Code mit mehreren Zeichen, aber Ihr Programm speichert jede Escape-Sequenz im Speicher als ein einziges Zeichen. Abschließend gibt es noch einen wichtigen Typ: object. Sie haben bereits gesehen, dass man Objekte erstellt, indem man Instanzen von Klassen erstellt. Jedes so erstellte Objekt kann einer Variablen vom Typ object zugewiesen werden. Im Verlauf dieses Kapitels werden Sie alles über Objekte und Variablen lernen, die auf Objekte verweisen. In Kapitel 9 lernen Sie mehr zum Verhältnis von char und byte.  double wird erheblich häufiger genutzt als float. Viele XAML- Eigenschaften nut- zen double-Werte. Ein »Literal« ist einfach eine Zahl, die Sie in Ihren Code eingeben. Die 5 im Ausdruck »int i = 5;« ist ein Literal. »M« steht für »money« (Geld) — kein Scherz! Der Windows-Rechner bietet den nützlichen »Programmierermodus«, indem Sie binäre und dezimale Werte nebeneinander sehen können! Bei Wäh- rungsbeträgen sollten Sie in der Regel decimal- Werte nutzen. Kopf- nuss
  5. 5. 144  Kapitel 4 Eine Variable ist wie ein Daten-to-go-Becher Alle Datentypen brauchen Speicherplatz. (Erinnern Sie sich an den Heap aus dem letzten Kapitel?) Ihre Aufgabe beinhaltet also, dass Sie sich darüber Gedanken machen, wie viel Speicherplatz Sie benötigen, wenn Sie in einem Programm einen String oder eine Zahl verwenden. Das ist einer der Gründe dafür, dass Sie Variablen verwenden. Über sie reser- vieren Sie so viel Platz im Speicher, wie Sie für Ihre Daten benötigen. Stellen Sie sich eine Variable wie einen Becher vor, in dem Sie Ihre Daten lagern. C# nutzt eine Menge unterschiedlicher Arten von Bechern, um unterschiedliche Arten von Daten festzuhalten. Und genau wie die verschiedenen Bechergrößen im Café haben auch Variablen unterschiedliche Größen. long int short byte 64 32 16 8 float double decimal 32 64 128 Zahlen mit Nachkommastellen werden anders gespeichert als ganze Zahlen. Die meisten Ihrer Zahlen mit Nachkommastellen können Sie mit float spei- chern, dem kleinsten Datentyp zur Speicherung von Dezimalzahlen. Wenn Sie eine höhere Genauigkeit brauchen, verwenden Sie double, und für das Schreiben von Finanzanwendungen, bei denen die Zahlen sehr genau sein müssen, sollten Sie den Typ decimal nutzen. Es geht aber nicht immer um Zahlen. (Sie würden ja auch nicht erwarten, einen heißen Kaffee in einem Plastikbecher zu bekommen und einen kalten in einem Papierbecher.) Der C#-Compiler kann auch mit Zeichen und anderen nicht numerischen Typen umgehen. Der Typ char speichert ein Zeichen, und string wird für viele aneinandergehängte Zeichen verwendet. Für eine string-Variable muss keine Größe vorgegeben werden. Sie wird so erwei- tert, dass sie so viele Daten aufnehmen kann, wie Sie darin speichern müssen. Der Typ bool wird zur Speicherung von Wahr/Falsch-Werten verwendet, wie Sie sie in Ihren if-Anweisungen verwendet haben. bool char string 8 16 long nutzen Sie fürZahlen, die echtgroß werden können. Für ganze Zahlen wird normalerweise int verwendet. Es speichert Zahlen bis 2.147.483.647. Das ist die Anzahl der Bits, die für Ihre Variable im Speicher reserviert werden, wenn Sie sie deklarieren. Das sind Typen für Zahlen mit Nachkommaanteil. Größere Typen speichern Werte mit mehr Nachkommastellen. Ein short speichert Zahlen bis 32.767. byte speichert Zahlen zwischen 0 und 255. von der Größe des Strings abhängig Einen Eisbecher float zum Mitnehmen, bitte Es landen nicht alle Daten auf dem Heap. Werttypen werden üblicherweise in einem anderen Speicherbereich festgehalten, der als Stack bezeichnet wird. In Kapitel 14 werden Sie mehr über ihn erfahren.
  6. 6. Sie sind hier 4  145 Typen und Referenzen Drei dieser Anweisungen lassen sich nicht kompilieren, weil sie versuchen, zu große Daten oder Daten des falschen Typs in eine Variable zu stecken. Kreisen Sie sie ein. 10 Kilo Daten in einem 5-Kilo-Sack Deklarieren Sie eine Variable eines bestimmten Typs, wird sie vom Compiler auch so betrachtet. Selbst wenn ein Wert nicht einmal in die Nähe der Obergrenze des Typs kommt, den Sie deklariert haben, blickt der Compiler nur auf den Becher, in dem er sich be- findet, nicht auf den Wert darin. Folgendes funktioniert also nicht: int meilenUnterDemMeer = 20000; short wenigerMeilen = meilenUnterDemMeer; 20.000 würde in einen short passen. Kein Problem. Aber da meilenUnterDemMeer als int deklariert ist, berücksichtigt der Compiler nur die maximale Größe eines int und sieht, dass diese zu groß für einen short-Container ist. Diese Übersetzung führt der Compiler nicht im Vorübergehen für Sie aus. Sie müssen sicherstellen, dass Sie den richtigen Typ für die Daten verwenden, mit denen Sie arbeiten. int stunden = 24; short y = 78000; bool fertig = ja; short RPM = 33; int kontostand = 345667 - 567; string drohung = Deine Mutter; byte tage = 365; long radius = 3; char initial = 'S'; string monate = 12; 20.000 int short Der Compiler sieht nur, dass ein int in einen short gesteckt werden soll (was nicht funktioniert). Um den Wert im Becher kümmert er sich nicht. Das ist vernünftig. Was wäre, wennSie später einen größeren Wert inden int-Becher steckten, der nichtmehr in den short-Becher passt?Der Compiler versucht nur, Sie zuschützen. Spitzen Sie Ihren Bleistift
  7. 7. 146  Kapitel 4 Drei dieser Anweisungen lassen sich nicht kompilieren, weil sie versuchen, zu große Daten oder Daten des falschen Typs in eine Variable zu stecken. Sie sollten sie einkreisen. short y = 78000; bool fertig = ja; byte tage = 365; In einen byte pas- sen nur Werte bis 256. Für diese Zahlbräuchten Sie einen short. Der Typ short speichert Zahlen von -32.767 bis 32.768. Die Zahl ist zu groß! Einem bool können Sie nur die Werte »true« oder »false« zuweisen. Auch eine Zahl der richtigen Größe können Sie nicht einfach irgendeiner Variablen zuweisen Schauen wir, was passiert, wenn Sie versuchen, einer int-Variablen einen decimal-Wert zuzuweisen. Erzeugen Sie ein neues Projekt und fügen Sie einen Button ein. ­Fügen Sie dann der Click()-Methode des Buttons folgende Zeilen hinzu: decimal meinDezimalWert = 10; int meinIntWert = meinDezimalWert; MessageBox.Show(meinIntWert ist + meinIntWert); 1 Sehen Sie sich an, wie die IDE herausfand, dass Ihnen wahrschein- lich eine Umwand- lung fehlt. Versuchen Sie, das Programm zu erstellen. Oh, Sie erhalten diesen Fehler:2 Lassen Sie den Fehler verschwinden, indem Sie einen Cast (auch Umwandlung genannt) einfügen, der den decimal zu einem int macht. Nachdem Sie die zweite Zeile in der nachfolgenden Weise geändert haben, lässt sich das Programm kompilieren und ausführen: int meinIntWert = (int) meinDezimalWert; 3 Umwandlungsaufruf Dies ist die Umwandlung von einem decimal-Wert in einen int. Tun Sie das! Mehr zu Werttypen in C# erfahren Sie hier: http://msdn.microsoft.com/de-de/library/s1ax56ch.aspx Lösung Spitzen Sie Ihren Bleistift Was ist passiert? Der Compiler lässt Sie einer Variablen keine Werte des falschen Typs zuweisen – selbst wenn die Vari- able den Wert aufnehmen könnte –, weil das der Grund für eine Unzahl von Fehlern ist. Der Compi- ler hilft Ihnen, indem er Ihnen den richtigen Weg weist. Wenn Sie umwandeln, ist das, als würden Sie dem Compiler ein Versprechen geben: »Ich weiß, die Typen sind unterschiedlich, aber in diesem Fall wird trotzdem nichts schiefgehen!« C# versucht dann, die Daten in die neue Variable zu packen.
  8. 8. Sie sind hier 4 147 Typen und Referenzen Wandeln Sie einen zu großen Wert um, passt C# ihn automatisch an Gerade haben Sie gesehen, dass ein decimal in einen int umgewandelt werden kann. Es ist sogar so, dass jede Zahl in jede andere Zahl umgewandelt werden kann. Aber das heißt nicht, dass der Wert bei der Umwandlung intakt bleibt. Wandeln Sie eine int-Variable, die auf 365 gesetzt ist, in einen byte um, ist 365 zu groß für den byte. Aber anstelle einer Fehlermeldung wird der Wert einfach überschlagen: Beispielsweise hat 256, in einen byte umgewandelt, den Wert 0, 257 den Wert 1, 258 den Wert 2 usw. bis 365, das zu 109 wird. Und sind Sie wieder bei 255 angekommen, »überschlägt« der umgewandelte Wert wieder zu null. In meinen Dialogfenstern habe ich ständig Zahlen und Strings kombiniert, seit ich in Kapitel 2 Schleifen kennen- gelernt habe! Habe ich mich da die ganze Zeit schon auf Umwandlungen verlassen? Ja! Der +-Operator wandelt um. Dort haben Sie den +-Operator verwendet, der automatisch eine Reihe von Um- wandlungen für Sie durchführt – aber er ist darin ziemlich gewandt. Wenn Sie mit + eine Zahl oder einen Booleschen Wert zu einem String hinzuaddieren, wandelt er den Wert automatisch in einen String um. Verwen- den Sie + (oder *, / oder -) mit unterschiedli- chen Typen, wird der kleinere Typ auto- matisch in den größeren umgewandelt. Hier ist ein Beispiel: int meinInt = 36; float meinFloat = 16.4F; meinFloat = meinInt + meinFloat; Da ein int in einen float passt, ein float aber nicht in einen int, wandelt der +-Ope- rator meinInt in einen float um, bevor meinFloat hinzuaddiert wird. Weisen Sie einem float einen Zahl- wert zu, müssen Sie ans Ende der Zahl F anhängen, um dem Compiler zu sagen, dass es ein float und kein double ist. Typen können nicht immer in andere Typen umgewandelt werden. Erzeugen Sie ein neues Projekt mit einem Button und stecken Sie in seine Methode diese Anweisungen. Beim Erstellen des Programms erhalten Sie Massen an Fehlern. Streichen Sie die Anweisungen durch, die zu Fehlern führen. So sehen Sie, welche Typen umgewandelt werden können und welche nicht! int einInt = 10; byte einByte = (byte)einInt; double einDouble = (double)einByte; bool einBool = (bool)einDouble; string einString = false; einBool = (bool)einString; einString = (string)einInt; einString = einInt.ToString(); einBool = (bool)einByte; einByte = (byte)einBool; short einShort = (short)einInt; char einChar = 'x'; einString = (string)einChar; long einLong = (long)einInt; decimal einDecimal = (decimal)einLong; einString = einString + einInt + einByte + einDouble + einChar; Typen und Referenzen Wandeln Sie selbst um!Wie die Umwandlung Zahlen »überschlägt«,ist kein Geheimnis – das können Sie selbst.Starten Sie den Windows-Rechner, wech-seln Sie in den Wissenschaftlich-Modusund berechnen Sie 365 Mod 256 (über den»Mod«-Button, der eine Modulo-Berech-nung durchführt). Sie erhalten 109. Spitzen Sie Ihren Bleistift
  9. 9. 148  Kapitel 4 Eine echte Konvertierung long l = 139401930; short s = 516; double d = l - s; d = d / 123.456; MessageBox.Show(Die Antwort ist + d); Der +-Operator kann den double in einen string umwandeln. Der --Operator zieht den short von dem long ab, und der =-Operator wandelt das Ergebnis in einen double um. Einige Umwandlungen macht C# automatisch Es gibt zwei wichtige Konvertierungen, die keine explizite Umwandlung verlangen. Die erste wird immer automatisch durchgeführt, wenn Sie arithmetische Operatoren verwenden, wie in diesem Beispiel: Außerdem konvertiert C# Typen automatisch für Sie, wenn Sie den +-Operator einsetzen, um Strings zu verketten (was ein- fach nur heißt, einen String an das Ende eines anderen anzuhän- gen, wie Sie es bei den Dialogfenstern gemacht haben). Wenn Sie mit dem +-Operator einen String mit etwas verketten, das einen anderen Typ hat, wandelt er Zahlen automatisch in Strings um. Sehen Sie hier ein Beispiel dazu – die ersten beiden Zeilen sind in Ordnung, aber die dritte lässt sich nicht kompilieren: long x = 139401930; MessageBox.Show(Die Antwort ist + x); MessageBox.Show(x); Der C#-Compiler spuckt einen Fehler aus, der irgendetwas von einem ungültigen Argument sagt (als Argument werden die Dinge bezeichnet, die Sie dem Parameter einer Methode übergeben). Das liegt daran, dass der Parameter für Messa- geBox.Show() ein string ist und dieser Code einen long, also den falschen Typ für diese Methode, übergibt. Aber Sie können ihn sehr leicht in einen String umwandeln, indem Sie seine ToString()-Methode aufrufen. Diese Methode ist ein Member jedes Werttyps und Objekts. (Alle Klassen, die Sie selbst erstellen, haben eine ToString()-Methode, die den Na- men der Klasse liefert.) Auf diese Weise können Sie x in etwas konvertieren, das ­MessageBox.Show() verwenden kann: MessageBox.Show(x.ToString()); Typen können nicht immer in andere Typen umgewandelt werden. Erzeugen Sie ein neues Projekt mit einem Button und stecken Sie in seine Methode diese Anweisungen. Beim Erstellen des Programms erhalten Sie Massen an Fehlern. Haben Sie die Anweisungen durchgestrichen, die zu Fehlern führen? So sehen Sie, welche Typen umgewandelt werden können und welche nicht! int einInt = 10; byte einByte = (byte)einInt; double einDouble = (double)einByte; bool einBool = (bool)einDouble; string einString = false; einBool = (bool)einString; einString = (string)einInt; einString = einInt.ToString(); einBool = (bool)einByte; einByte = (byte)einBool; short einShort = (short)einInt; char einChar = 'x'; einString = (string)einChar; long einLong = (long)einInt; decimal einDecimal = (decimal) einLong; einString = einString + einInt + einByte + einDouble + einChar; Lösung Spitzen Sie Ihren Bleistift
  10. 10. Sie sind hier 4 149 Typen und Referenzen Beim Aufruf einer Methode müssen die Variablen den Typen der Parameter entsprechen Versuchen Sie, MessageBox.Show(123) aufzurufen, übergeben Sie Message- Box.Show() ein Literal (123) statt eines Strings. Die IDE lässt Sie Ihr Programm nicht erstellen. Stattdessen meldet sie Ihnen einen Fehler: »1-Argument: kann nicht von ›int‹ in ›string‹ konvertiert werden.« Manchmal kann C# die Umwandlung automatisch durchführen – beispielsweise wenn eine Methode einen int erwartet, Sie ihr aber einen short übergeben –, aber bei int- und string-Werten kann es das nicht. Aber MessageBox.Show() ist nicht die einzige Methode, die Ihnen Compiler-Fehler meldet, wenn Sie versuchen, ihr eine Variable zu übergeben, deren Typ dem Parameter nicht entspricht. Das tun alle Methoden, sogar die, die Sie selbst schreiben. Sie können das testen, indem Sie diese absolut zulässige Methode in eine Klasse eingeben: Liefert Ihnen der Compiler einen »Ungültige Argu­ mente«­Fehler, haben Sie ver­ sucht, eine Metho­ de mit Werten aufzurufen, deren Typen den Metho­ denparametern nicht entsprechen. public int MeineMethode(bool jaNein) { if (jaNein) { return 45; } else { return 61; } } Sie funktioniert wunderbar, solange Sie ihr übergeben, was sie erwartet (einen bool) – rufen Sie MeineMethode(true) oder MeineMethode(false) auf, kompiliert das Programm problemlos. Aber was ist, wenn Sie stattdessen einen int oder einen string übergeben? Die IDE liefert Ihnen einen ähnlichen Fehler wie den, den Sie erhalten haben, als Sie Message- Box.Show() 123 übergeben hatten. Übergeben Sie jetzt einen Booleschen Wert, aber versuchen Sie, den Rückgabewert einem string zuzuweisen oder an MessageBox. Show() zu übergeben. Auch das geht nicht – die Methode liefert einen int, nicht den string, den MessageBox.Show() erwartet. Zur Erinnerung – der Code, der diese Methode auf- ruft, muss den Parameter nicht als Variable namens jaNein angeben. Er muss einfach nur einen Booleschen Wert oder eine beliebige Boolesche Variable angeben. jaNein heißt er lediglich innerhalb der Methode. Sie sind hier 4 149 , den MessageBox.Show() erwartet. if-Anweisungen prüfen immer auf Wahrheit Ist Ihnen aufgefallen, dass wir die if-Anweisung folgendermaßen geschrieben haben: if (jaNein) { Wir mussten nicht explizit »if (jaNein == true)« sagen. Grund dafür ist, dass eine if-Anweisung immer prüft, ob etwas wahr ist. Wollen Sie prüfen, ob etwas falsch ist, nutzen Sie das ! (ein Ausrufe- zeichen bzw. den NICHT-Operator). »if (!jaNein)« ist das Gleiche wie »if (jaNein == false)«. In unseren Codebeispielen werden wir von jetzt an in der Regel »if (jaNein)« oder »if (!jaNein)« verwenden und nicht explizit prüfen, ob ein Boolescher Wert true oder false ist. Einer Variablen, einem Parameter oder einem Feld mit dem Typ object können Sie alles zuweisen. Parameter sind das, was Sie in Methoden definieren, Argumente sind das, was Sie ihnen übergeben. Eine Methode kann einen int- Parameter haben und dennoch ein byte-Argument akzeptieren. Das haben Sie im »Die Menschheit retten«-Code gemacht. Nehmen Sie sich diesen noch einmal vor und schauen Sie, ob Sie die ent- sprechende Stelle finden.
  11. 11. 150  Kapitel 4 In C# gibt es ungefähr 77 reservierte Wörter. Diese Wörter werden durch den C#-Compiler reserviert und dürfen nicht als Variablennamen verwendet werden. Wenn Sie mit dem Buch durch sind, werden Sie sie alle gut kennen. Hier sind einige, die Sie schon benutzt haben. Schreiben Sie, was Ihrer Meinung nach diese Wörter in C# tun. Diese Plätze sind reserviert namespace for class public else new using if while Antworten auf Seite 182. Eigentlich gibt Ihnen C# eine Möglichkeit, reservierte Schlüsselwörterals Variablennamen zu nutzen, indem Sie ihnen ein @ voranstellen. Daskönnen Sie auch mit nicht reservierten Namen tun, wenn Sie wollen. Übung
  12. 12. Sie sind hier 4  151 Typen und Referenzen Erzeugen Sie einen Reisekostenerstattungsrechner für Geschäftsreisen. Der Benutzer sollte den Anfangs- und Endstand des Tachometers eingeben können. Auf Basis dieser beiden Zahlen wird der Rechner die angefallenen Kilometer berechnen und daraus ermitteln, wie hoch der Erstattungsbetrag ist, wenn für jeden angefallenen Kilometer 0,39 € gezahlt wird. Beginnen Sie mit einem neuen Windows-Projekt. Geben Sie dem Formular folgende Gestalt: 1 Erzeugen Sie die Felder, die Sie für den Rechner benötigen. Stecken Sie die Felder in die Klassendefinition am Anfang von Form1. Sie brauchen zwei Felder für ganze Zahlen, die den Tachometer-Anfangsstand und -Endstand speichern. Nen- nen Sie diese tachoAnfangsstand und tachoEndstand. Außerdem brauchen Sie drei Zahlen, die Nachkommastellen aufnehmen können. Nehmen Sie jeweils den Typ double und nennen Sie sie gefahreneKM, erstattungsSatz und erstattungsBetrag. Setzen Sie den Wert für erstattungsSatz auf 0.39. 2 Der Bereich für diese Feldersollte 1 bis 999.999 umfassen. Lassen Sie die Minimieren-und Maximieren-Buttonsverschwinden. Dieses Label ist 10 Punkte groß und fett. Klicken Sie doppelt auf den Button, wenn Sie das Formular fertig haben, um dem Projekt etwas Code hinzuzufügen. Bringen Sie den Rechner zum Funktionieren. Fügen Sie der Methode button1_Click() Code zu folgenden Zwecken hinzu: ≥≥ Stellen Sie sicher, dass die Zahl im Feld tachoAnfangsstand kleiner als die Zahl im Feld tachoEndstand ist. Lassen Sie andernfalls ein Dialogfenster mit der Mel- dung »Der Anfangsstand muss kleiner als der Endstand sein.« anzeigen. Geben Sie diesem Dialog den Titel »Keine Berechnung möglich«. ≥≥ Ziehen Sie mit folgenden Zeilen den Anfangsstand vom Endstand ab und multipli­ zieren Sie ihn dann mit dem Erstattungssatz: gefahreneKM = tachoEndstand -= tachoAnfangsstand; erstattungsBetrag = gefahreneKM *= erstattungsSatz; label4.Text = erstattungsBetrag + €; 3 Führen Sie die Anwendung aus. Prüfen Sie, ob der Rechner korrekte Werte liefert. Probieren Sie, den Anfangsstand größer als den Endstand zu machen, und schauen Sie, ob Ihr Dialogfenster angezeigt wird. 4 Übung
  13. 13. 152  Kapitel 4 Hier ist der Code für den ersten Teil der Übung. Etwas stimmt nicht … public partial class Form1 : Form { int tachoAnfangsstand; int tachoEndstand; double gefahreneKM; double erstattungsSatz = 0.39; double erstattungsBetrag; public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e){ tachoAnfangsstand = (int)numericUpDown1.Value; tachoEndstand = (int)numericUpDown2.Value; if (tachoAnfangsstand = tachoEndstand){ gefahreneKM = tachoEndstand -= tachoAnfangsstand; erstattungsBetrag = gefahreneKM *= erstattungsSatz; label4.Text = erstattungsBetrag + €; } else { MessageBox.Show( Der Anfangsstand muss kleiner als der Endstand sein., Keine Berechnung möglich); } } } Haben Sie daran gedacht, den decimal-Wert des NumericUpDown-Steuer­ elements in einen int ­umzuwandeln? Ja, der Punkt ist richtig. Das und nicht das Komma ist der Dezimaltrenner, den C# verwendet - genau wie jede andere Programmiersprache. Darauf müssen Sie achten, wenn Sie in Ihrem Code Gleit- kommazahlen literal angeben. int funktioniert wunderbar fürganze Zahlen. Diese Zahl könntebis 999.999 gehen. Ein short oderein byte würde also nicht reichen. Dieser Block soll berechnen, wie viele Kilometer zurückgelegt wurden, und diese dann mit dem Erstattungssatz multiplizieren. Dieser Button scheint zu funktionieren, birgt eigentlich aber ein ziemlich großes Problem. Sehen Sie es? Wir haben hier eine alternative Form der Methode MessageBox. Show() verwendet. Wir haben ihr zwei Parameter gegeben, der erste ist die anzuzeigende Nachricht und der zweite der Text der Titelleiste. lösung zur Übung
  14. 14. Sie sind hier 4  153 Typen und Referenzen Fügen Sie dem Formular einen weiteren Button hinzu. Gehen wir dem Problem auf den Grund, indem wir dem Formular einen Button hinzufügen, der den Wert des Felds gefahreneKM anzeigt (dazu könnten Sie auch den Debugger nutzen). 1 Eine Zeile Code sollte Reichen. Wir müssen das Formular im Prinzip nur dazu bringen, die Variable gefahreneKM anzuzeigen, oder? Das sollte sich eigentlich mit dieser Zeile erledigen lassen: private void button2_Click(object sender, EventArgs e) { Messagebox.Show(gefahreneKM + KM, Zurückgelegte Kilometer); } 2 Klicken Sie, wenn Sie das Formular fertig haben, doppelt auf den Button Kilometer anzeigen, um dem Projekt etwas Code hinzuzufügen. Führen Sie Es aus. Geben Sie ein paar Werte ein und schauen Sie, was passiert. Geben Sie zunächst einen Anfangsstand und einen Endstand ein und klicken Sie auf den Berechnen-Button. Klicken Sie dann auf den Button »Kilome- ter anzeigen«, um zu sehen, was im Feld gefahreneKM gespeichert ist. 3 Hmm, da stimmt was nicht … Ganz gleich, was Sie tun, die Kilometeranzahl entspricht immer dem Erstattungsbetrag. Warum? 4 Nach einem Klick auf Berechnen soll dieser Button dazu verwendet werden können, in einem Dialogfenster die zurückgelegten Kilometer anzuzeigen. Tun Sie dasDen Kilometerrechner debuggen Irgendetwas mit dem Kilometerrechner stimmt nicht. Wenn Ihr Code nicht auf die erwartete Weise funktioniert, gibt es immer einen Grund dafür. Sie sind dafür verantwortlich, diesen Grund zu fin- den. Untersuchen wir, was schiefgelaufen ist, und schauen wir, ob wir es reparieren können.
  15. 15. 154 Kapitel 4 private void button1_Click(object sender, EventArgs e) { tachoAnfangsstand = (int)numericUpDown1.Value; tachoEndstand = (int)numericUpDown2.Value; if (tachoAnfangsstand = tachoEndstand){ gefahreneKM = tachoEndstand -= tachoAnfangsstand; erstattungsBetrag = gefahreneKM *= erstattungsSatz; label4.Text = erstattungsBetrag + €; } else { MessageBox.Show( Der Anfangsstand muss kleiner als der Endstand sein., Keine Berechnung möglich); } } Operatoren in der Warteschleife Sehen Sie sich einmal genau den Operator an, den wir verwendet haben, um den Tachometer- Anfangsstand vom Tachometer-Endstand abzuziehen (–=). Das Problem ist, dass er nicht nur subtrahiert, sondern der Variablen links des Minuszeichens auch einen Wert zuweist. Das Gleiche passiert in der Zeile, in der wir die Anzahl der zurückgelegten Kilometer mit der Erstat- tungsrate multiplizieren. Wir müssen –= und *= lediglich durch – bzw. * ersetzen. Einen Operator mit = kombinieren Das nennt man einen zusammengesetzten Operator. Er zieht tachoAnfangsstand von tachoEnd- stand ab, weist den neuen Wert aber auch gleichzeitig tachoEndstand und gefahreneKM zu. Können Ihnen gute Variablen hier helfen? Unbedingt! Sehen Sie sich genau an, was die einzelnen Variablen vermeintlich tun. Der Name gefahreneKM gibt Ihnen bereits eine Menge Hinweise – Sie wissen, dass es diese Variable ist, die das Formular falsch anzeigt, und haben eine gute Vorstellung davon, wie dieser Wert berechnet werden sollte. Das können Sie also nutzen, wenn Sie Ihren Code durchsuchen, um den Fehler aufzuspüren. Es wäre viel schwerer, das Problem zu finden, sähen die fehlerhaften Zeilen stattdessen so aus: mT = eM -= sM; aO = mT *= rR; gefahreneKM = tachoEndstand - tachoAnfangsstand; erstattungsBetrag = gefahreneKM * erstattungsSatz; Das ist besser – jetzt verändert der Code tachoEndstand und gefahreneKM nicht mehr. Variablen mit Namen wie diesesind im Grunde nutzlos, wenn esdarum geht, Ihnen etwas überihren Zweck mitzuteilen.
  16. 16. Sie sind hier 4  155 Typen und Referenzen Auch für Objekte braucht man Variablen Bislang haben wir Objekte von den anderen Typen getrennt betrachtet. Aber Objekte sind einfach nur eine andere Art von Daten, die Ihr Code genau so behandelt wie Zahlen, Strings und Boolesche Werte. Er nutzt Variablen, um mit ihnen zu arbeiten. Einen int verwenden Ein Objekt verwenden Schreiben Sie eine Anweisung, die ein Objekt ­deklariert. Hund rex; 1Schreiben Sie eine Anweisung, die einen int deklariert. int einInt; 1 Weisen Sie der Variablen ein Objekt zu. rex = new Hund(); 2Weisen Sie der Variablen einen Wert zu. einInt = 3761; 2 Prüfen Sie eins der Felder des Objekts. while (rex.Zufrieden) { 3Nutzen Sie den Wert in Ihrem Code. while (i einInt) { 3 Haben Sie eine Klasse wie Hund, nutzen Sie diese in der Variablendeklaration als Typ. Ein Objekt ist einfach eine weitere Art von Variable, die Ihr Programm verwenden kann. Muss Ihr Programm mit einer richtig großen ganzen Zahl arbeiten, verwenden Sie einen long, und muss es mit einer kleinen ganzen Zahl arbeiten, nehmen Sie einen short. Braucht es einen Ja/Nein-Wert, verwenden Sie einen boolean. Benötigt es jedoch etwas, das bellt und Sitz macht, verwenden Sie einen Hund. Ganz gleich, mit Daten welcher Art Ihr Programm arbeiten muss, es verwendet immer eine Variable. Es spielt also keine Rolle, ob ich mit ei- nem Objekt oder einem numerischen Wert arbeite. Ich verwende in beiden Fällen eine Variable, wenn ich etwas zur späteren ­Verwendung speichern muss.
  17. 17. 156  Kapitel 4 Typ-Objekt 1 Die Referenz erhalten Um ein neues Objekt zu erstellen, verwenden Sie Code wie new Typ. Aber das ist nicht genug. Obgleich dieser Code ein neues Typ-Objekt auf dem Heap erstellt, gibt er Ihnen noch keine Möglichkeit, auf dieses Objekt zuzugreifen. Sie benötigen eine Referenz auf dieses Objekt. Sie erzeugen deswegen eine Referenzvariable: eine Variable des Typs Typ mit einem Namen wie tim. tim ist also eine Referenz auf das neue Typ-Objekt, das Sie erstellt haben. Jedes Mal, wenn Sie diesen bestimmten Typ verwenden möchten, können Sie ihn mit der Referenzvariablen namens tim referenzieren. Wenn Sie eine Variable haben, die einen Objekttyp hat, ist es eine Referenzvariable: eine Referenz auf ein bestimmtes Objekt. Werfen Sie einen Blick darauf: Mit Referenzvariablen auf Objekte verweisen public partial class Form1 : Form { Typ tim; public Form1() { InitializeComponent(); tim = new Typ(); } Das wird als Instantiierung des Objekts bezeichnet. Hier ist der Heap vor der Ausführung Ihres Codes. Hier ist der Heap nach Ausführung Ihres Codes. Es gibt ein Objekt, auf das die Variable tim verweist. Diese Variable heißt tim, sie wird ein Objekt des Typs Typ referenzieren. Das ist die Referenz- variable … … und das ist das Objekt, auf das tim jetzt verweist. Dieses Typ-Objekt kann NURüber die Referenzvariable timreferenziert werden. Das Erstellen einer Referenz ist, als erstelle man ein Etikett mit einer Etikettiermaschine – statt es an Ihr Zeug zu kleben, nutzen Sie es, um ein Objekt zu etikettieren, damit Sie später darauf verweisen können.
  18. 18. Sie sind hier 4  157 Typen und Referenzen In der Küche haben Sie wahrscheinlich eine Dose für Salz und eine für Zucker. Würden Sie die Etiketten darauf tauschen, könnte das dazu führen, dass Sie das eine oder andere Essen vergeigen – den selbst wenn die Etiketten vertauscht werden, bleibt der Inhalt gleich. Referenzen sind wie Etiketten. Sie können Etiketten herumreichen, an unterschiedliche Dinge heften, aber das Objekt stellt die Methoden und Daten, nicht die Referenz selbst. Referenzen sind wie Etiketten für Ihr Objekt Das ist ein Objekt des Typs Typ. Es ist ein EINZELNES Objekt, auf das VIELE Referenzen zeigen. Auf ein Objekt verweist man nie direkt. Code wie Typ.GeldGeben() können Sie beispielsweise nicht schreiben, wenn Typ Ihr Objekttyp ist. Der C#-Compiler weiß nicht, von welchem Typ Sie hier reden, da es auf dem Heap mehrere Instan- zen von Typ geben könnte. Sie brauchen also eine Referenzvariable tim, der Sie eine spezifische Instanz zuweisen können, z. B. Typ tim = new Typ(). Jetzt können Sie (nicht statische) Methoden wie tim.GeldGeben() verwenden. tim verweist auf eine bestimmte Instanz der Klasse Typ, und der C#-Compiler weiß genau, welche Instanz er verwenden soll. Wie Sie oben gesehen haben, können mehrere Etiketten auf die gleiche Instanz zeigen. Sie könnten also Typ papa = tim sagen und dann papa.GeldGeben() aufrufen. Auch das geht – Tims Sohn macht das jeden Tag! Die button1_Click-Methode von Form1referenziert dieses Objekt über eineVariable mit dem Namen »tim« Es gibt viele verschiedene Referenzenauf dieses Objekt, weil viele verschie-dene Methoden es für unterschiedli-che Dinge verwenden. Jede Referenzhat einen anderen Namen, der in ihremjeweiligen Kontext sinnvoll ist. Jedes dieser Etiketten ist eine Referenzvariable. All diese Variablen zeigen aber auf das GLEICHE Typ-Objekt. Muss Ihr Code mit Objekten im Speicher arbeiten, nutzt er eine Referenz, d. h. eine Variable, deren Typ die Klasse des Objekts ist, auf das sie verweist. Eine Referenz ist wie ein Etikett, das Ihr Code nutzt, um mit einem bestimmten Objekt zu reden. Eine andere Klasse verweist auf diese Instanz der Klasse Typ über eine Variable namens »papa«. Typ papa = tim;
  19. 19. 158  Kapitel 4 Typ-Objekt Typ-Objekt 2 Typ-Objekt 1 Typ-Objekt 2 Trägt ein Objekt kein einziges Etikett mehr, können Programme nicht mehr auf dieses Objekt zugreifen. Das heißt, dass C# dieses Objekt für die Müllabfuhr, die wir, wie in Programmiererkreisen üblich, Garbage Col­ lection nennen werden, vormerkt. So bezeichnet man den Mechanismus, über den C# nicht referenzierte Objekte loswird und den Speicher freigibt, den diese Objekte für Ihr Programm belegt haben. Ein Objekt bleibt nur so lange auf dem Heap, wie es Referenzen da­ rauf gibt. Ver­ schwindet die letzte Referenz, verschwindet auch das Objekt. Gibt es keine Referenzen mehr, holt die Müllabfuhr Ihr Objekt Wenn Sie die »new«-Anweisung nutzen, weisen Sie C# an, ein Objekt zu erstellen. Nehmen Sie eine Referenzvariable wie tim und weisen ihr dieses Objekt zu, ist das, als würden Sie ein neues Label an das Objekt heften. Hier ist etwas Code, der ein Objekt erzeugt. Typ tim = new Typ() { Name = Tim, Geld = 50 }; 1 Erzeugen wir jetzt ein zweites Objekt. Typ tom = new Typ() { Name = Tom, Geld = 75 }; 2 Ändern wir die Referenz auf das erste Objekt und las- sen wir sie auf das zweite zeigen. tim = tom; 3 Jetzt zeigt tim auf das gleiche Objekt wie tom. Vielen Dank, Herr Kammerjäger Jetzt haben wir zwei Typ-Instanzenund zwei Referenzvariablen: eine fürjede Typ-Instanz. Aber es gibt keine Referenz auf das erste Typ-Objekt mehr … … C# merkt es des- wegen für die GarbageCollection vor, die es irgendwann löscht. Undschwups, weg ist es! »Tim« 50 »Tom« 75 »Tim« 50 »Tom« 75
  20. 20. Sie sind hier 4  159 Typen und Referenzen Typ-Kreuz- worträtsel Machen Sie eine Pause, lehnen Sie sich zurück und geben Sie Ihrer rechten Gehirnhälfte etwas zu tun. Und zwar wieder mit dem Ihnen schon bekannten Kreuzworträtsel. Alle Lösungswörter stammen aus diesem Kapitel. Wenn Sie fertig sind, können Sie umblättern, um sich dem Rest dieses Kapitels zu widmen. Antworten auf Seite 183. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Waagerecht 3. Der Typ, der die größten Zahlen speichern kann. 7. n und r sind _____-Sequenzen. 8. Wird das für eine Variable nicht gesetzt, lässt sich Ihr Programm nicht kompilieren. 10. Die Deklaration einer Variablen beginnt immer damit. 12. Der Typ, der nur ein einzelnes Zeichen speichert. 13. Jedes Objekt hat diese Methode, die es in einen String umwandelt. 14. Das tun Sie, wenn Sie mit dem +-Operator zwei Strings zusammenkleben. 15. Die Deklaration und die ____________ einer Variablen können zu einer Anweisung zusammengefasst werden. 16. Zeigen auf ein Objekt keine Referenzen mehr, wird es von der ____________-Collection aus dem Heap entfernt. Senkrecht 1. »namespace«, »for«, »while«, »using« und »new« sind alles Beispiele für _____________ Wörter. 2. Das machen die arithmetischen Operatoren für Sie mit Typen automatisch. 4. Einer Variablen dieses Typs können Sie jeden Wert zuweisen. 5. Der zweite Teil einer Variablendeklaration. 6. Was Ihr Programm nutzt, um mit Daten zu arbeiten, die im Speicher sind. 9. Eine Variable, die auf ein Objekt zeigt. 11. Die vier Typen für ganze Zahlen, die nur positive Zahlen speichern. 12. Das, was (int) in folgender Codezeile macht: x = (int) y; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Waagerecht 3. Der Typ, der die größten Zahlen speichern kann. 7. n und r sind _____-Sequenzen. 8. Wird das für eine Variable nicht gesetzt, lässt sich Ihr Programm nicht kompilieren. 10. Die Deklaration einer Variablen beginnt immer damit. 12. Der Typ, der nur ein einzelnes Zeichen speichert. 13. Jedes Objekt hat diese Methode, die es in einen String umwandelt. 14. Das tun Sie, wenn Sie mit dem +-Operator zwei Strings zusammenkleben. 15. Die Deklaration und die ____________ einer Variablen können zu einer Anweisung zusammengefasst werden. 16. Zeigen auf ein Objekt keine Referenzen mehr, wird es von der ____________-Collection aus dem Heap entfernt. Senkrecht 1. »namespace«, »for«, »while«, »using« und »new« sind alles Beispiele für _____________ Wörter. 2. Das machen die arithmetischen Operatoren für Sie mit Typen automatisch. 4. Einer Variablen dieses Typs können Sie jeden Wert zuweisen. 5. Der zweite Teil einer Variablendeklaration. 6. Was Ihr Programm nutzt, um mit Daten zu arbeiten, die im Speicher sind. 9. Eine Variable, die auf ein Objekt zeigt. 11. Die vier Typen für ganze Zahlen, die nur positive Zahlen speichern. 12. Das, was (int) in folgender Codezeile macht: x = (int) y; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Waagerecht 3. Der Typ, der die größten Zahlen speichern kann. 7. n und r sind _____-Sequenzen. 8. Wird das für eine Variable nicht gesetzt, lässt sich Ihr Programm nicht kompilieren. 10. Die Deklaration einer Variablen beginnt immer damit. 12. Der Typ, der nur ein einzelnes Zeichen speichert. 13. Jedes Objekt hat diese Methode, die es in einen String umwandelt. 14. Das tun Sie, wenn Sie mit dem +-Operator zwei Strings zusammenkleben. 15. Die Deklaration und die ____________ einer Variablen können zu einer Anweisung zusammengefasst werden. 16. Zeigen auf ein Objekt keine Referenzen mehr, wird es von der ____________-Collection aus dem Heap entfernt. Senkrecht 1. »namespace«, »for«, »while«, »using« und »new« sind alles Beispiele für _____________ Wörter. 2. Das machen die arithmetischen Operatoren für Sie mit Typen automatisch. 4. Einer Variablen dieses Typs können Sie jeden Wert zuweisen. 5. Der zweite Teil einer Variablendeklaration. 6. Was Ihr Programm nutzt, um mit Daten zu arbeiten, die im Speicher sind. 9. Eine Variable, die auf ein Objekt zeigt. 11. Die vier Typen für ganze Zahlen, die nur positive Zahlen speichern. 12. Das, was (int) in folgender Codezeile macht: x = (int) y;
  21. 21. 160  Kapitel 4 Hund-Obje kt1 Hund-Obje kt3 Hund-Obje kt1 Hund-Obje kt2 So viele Etiketten Wenn Sie damit beginnen, Ihre Referenzvariablen herumzureichen, müssen Sie aufpassen. Oft scheint es, als würden Sie eine Variable einfach auf ein anderes Objekt zeigen lassen. Aber das kann dazu führen, dass dabei alle Referenzen auf ein Objekt gelöscht werden. Das ist nicht notwendigerweise falsch, aber auch nicht immer das, was Sie eigentlich wollten. Werfen Sie einen Blick darauf: Mehrere Referenzen und ihre Nebenwirkungen Hund-Obje kt1 Hund hasso = new Hund(); hasso.Rasse = Windhund; 1 Hund fido = new Hund(); fido.Rasse = Beagle; Hund rex = hasso; 2 Hund lucky = new Hund(); lucky.Rasse = Dackel; fido = hasso; 3 hasso ist ein Hund-Objekt mit dem Rasse-Wert Windhund. fido ist ein weiteres Hund- Objekt. rex dagegen ist nur eine weitere Referenz auf das erste Objekt. lucky ist das dritte Objekt. Aber fido zeigt jetzt auf Objekt 1. Es gibt keine Referenzen auf Objekt 2 mehr. Für das Programm ist es erledigt. Objekte:______ Referenzen:_____ Objekte:______ Referenzen:_____ Objekte:______ Referenzen:_____ 1 1 2 3 2 4
  22. 22. Sie sind hier 4  161 Typen und Referenzen Hund hasso = new Hund(); hasso.Rasse = Windhund; Hund rantanplan = new Hund(); Hund fido = new Hund(); Hund quentin = fido; 1 Hund rex = new Hund(); rex.Rasse = Dackel; rex = hasso; 2 Hund lucky = new Hund(); lucky.Rasse = Beagle; Hund charlie = fido; fido = hasso; 3 Objekte:______ Referenzen:_____ Objekte:______ Referenzen:_____ rantanplan = lucky; Hund otto = new Hund(); otto.Rasse = Mops; 4 Objekte:______ Referenzen:_____ charlie = otto; lucky = rantanplan; 5 Objekte:______ Referenzen:_____ Objekte:______ Referenzen:_____ Jetzt sind Sie an der Reihe. Hier ist ein langer Codeblock. Ermitteln Sie, wie viele Objekte und Referenzen es nach den einzelnen Phasen gibt. Zeichnen Sie auf der rechten Seite ein Bild mit den Objekten und Etiket- ten auf dem Heap. Spitzen Sie Ihren Bleistift
  23. 23. 162  Kapitel 4 Hund-Obj ekt5 Hund-Objekt3 Hund-Obj ekt1 Hund-Obj ekt4 Hund-Obj ekt1 Hund-Obj ekt3 Hund-Obje kt5 Hund-Obj ekt4 H und-Obj ekt2 Hund-Obje kt3 Hund-Obj ekt1 Hund-Obj ekt4 Hund-Ob jekt3 Hund-Obj ekt1 Hund-Obj ekt2 Hund-Ob jekt3 Typen und Referenzen Hund hasso = new Hund(); hasso.Rasse = Windhund; Hund rantanplan = new Hund(); Hund fido = new Hund(); Hund quentin = fido; 1 Hund rex = new Hund(); rex.Rasse = Dackel; rex = hasso; 2 Hund lucky = new Hund(); lucky.Rasse = Beagle; Hund charlie = fido; fido = hasso; 3 Objekte:______ Referenzen:_____ Objekte:______ Referenzen:_____ rantanplan = lucky; Hund otto = new Hund(); otto.Rasse = Mops; 4 Objekte:______ Referenzen:_____ charlie = otto; lucky = rantanplan; 5 Objekte:______ Referenzen:_____ Objekte:______ Referenzen:_____ Jetzt sind Sie an der Reihe. Hier ist ein langer Codeblock. Sie sollten ermitteln, wie viele Objekte und Referenzen es nach den einzelnen Phasen gibt, und auf der rechten Seite ein Bild mit den Objekten und Etiketten auf dem Heap zeichnen. 3 3 4 7 4 8 4 8 Es wird ein neues Hund- Objekt erzeugt, aber rex ist die einzige Referenz darauf. Nach rex = hasso ist dieses Objekt wieder verschwunden. Hier wird ein neues Hund- Objekt erstellt, das erhalten bleibt, weil die Referenz darauf nicht überschrieben wird. charlie wurde gleich fido gesetzt, als fido noch auf Objekt 3 verwies. Nachdem fido gleich hasso gesetzt wurde, verweist fido auf Objekt 1, charlie hingegen weiter auf Objekt 3. Hier werden nur Referenzen verschoben, aber keine neuen Objekte erzeugt. lucky gleich rantanplan zu setzen, änderte nichts, da beide Variablen bereits auf das gleiche Objekt zeigen. 4 5 Hund-Obj ekt1 H und-Obj ekt2 Objekt 2 ver- liert seine letzte Referenz und verschwindet. Weil lucky jetzt auf das gleiche Objekt wie rantanplan verweist, gibt es keine Referenz auf das alte Objekt von rantanplan mehr. Lösung Spitzen Sie Ihren Bleistift
  24. 24. Sie sind hier 4 163 Typen und Referenzen Erstellen Sie ein Programm mit einer Elefant-Klasse. Erzeugen Sie zwei Elefant- Instanzen und tauschen Sie dann die Referenzvariablen, die auf sie zeigen, ohne dass eine der Elefant-Instanzen dabei ein Fall für die Müllabfuhr wird. Erstellen Sie ein neues Windows Forms-Anwendung-Projekt. Geben Sie dem Formular diese Gestalt: 1 Erzeugen Sie die Klasse Elefant. Fügen Sie dem Projekt die Klasse Elefant hinzu. Sehen Sie sich das Klassendiagramm für Elefant an – Sie brauchen ein int-Feld namens Ohrengröße und ein string-Feld namens Name. (Achten Sie darauf, dass beide public sind.) Fügen Sie dann die Methode WerBinIch() hinzu, die ein Dialogfens- ter anzeigt, das Ihnen den Namen und die Länge des Elefantenohrs sagt. 2 Erzeugen Sie zwei Elefant-Instanzen und -Referenzen. Fügen Sie Form1 (direkt unter der Klassendeklaration) zwei Elefant-Felder namens kunibert und kunigunde hinzu. Initialisieren Sie diese mit dem korrekten Namen und einer Ohrengröße. Hier sind die Elefant-Objektinitialisierer für Ihr Formular: kunigunde = new Elefant() { Name = Kunigunde, Ohrengröße = 63 }; kunibert = new Elefant() { Name = Kunibert, Ohrengröße = 81 }; 3 Machen Sie die Buttons »Kunibert« und »Kunigunde« funktionsfähig. Lassen Sie den Kunibert-Button kunibert.WerBinIch() und den Kunigunde-Button kunigunde.WerBinIch() aufrufen. 4 Richten Sie den Tauschen-Button ein. Jetzt kommt der schwere Teil. Bringen Sie den Tauschen-Button dazu, die beiden Referenzen zu tauschen, damit die Variablen kunibert und kunigunde durch einen Klick auf Tauschen die Objekte tauschen und eine »Objekte getauscht«-Meldung angezeigt wird. Testen Sie das Programm, indem Sie auf Tauschen und dann auf die beiden anderen Buttons klicken. Nach dem ersten Klick auf Tauschen sollte der Button Kunibert das Dialogfenster für Kunigunde anzeigen. Nach dem nächs- ten Klick auf Tauschen sollte alles wieder beim Alten sein. 5 Elefant Name Ohrengröße WerBinIch() Ein Klick auf den Button »Kunigunde« ruft kunigunde.WerBinIch() auf. Diese Methode zeigt dieses Dialogfenster an. C# löscht alle Objekte, auf die es keine Referenzen mehr gibt. Ein kleiner Hinweis: Wenn Sie ein Glas Bier in ein Glas schütten wollen, in dem im Moment Wasser ist, brauchen Sie ein drittes Glas ... Hier ist das Klassendiagramm fürdie zu erstellende Klasse Elefant. Die Methode WerBinIch() sollte diesen Dialog öffnen. Prüfen Sie, ob der Text die Ohrengröße enthält und in der Titelleiste der Name steht. Übung
  25. 25. 164 Kapitel 4 Erstellen Sie ein Programm mit einer Elefant-Klasse. Sie erzeugen Sie zwei Elefant-Instanzen und tauschen dann die Referenzvariablen, die auf sie zeigen, ohne dass eine der Elefant-Instanzen dabei ein Fall für die Müllabfuhr wird. Warum haben wir die Methode Tauschen() nicht in die Klasse Elefant eingefügt? using System.Windows.Forms; class Elefant { public int Ohrengröße; public String Name; public void WerBinIch() { MessageBox.Show(Meine Ohren sind + Ohrengröße + cm lang., Name + sagt); } } public partial class Form1 : Form { Elefant kunigunde; Elefant kunibert; public Form1() { InitializeComponent(); kunigunde = new Elefant() { Name = Kunigunde, Ohrengröße = 63 }; kunibert = new Elefant() { Name = Kunibert, Ohrengröße = 81 }; } private void button1_Click(object sender, EventArgs e) { kunibert.WerBinIch(); } private void button2_Click(object sender, EventArgs e) { kunigunde.WerBinIch(); } private void button3_Click(object sender, EventArgs e) { Elefant halter; halter = kunibert; kunibert = kunigunde; kunigunde = halter; MessageBox.Show(Objekte getauscht); } } Für diese Referenz gibt es keine new-Anweisung, weil wir keine weitere Elefant-Instanz brauchen. Lassen Sie einfach kuni- bert auf kunigunde zeigen, gibt es keine Referenz auf Kunibert mehr. Sein Objekt geht also verloren. Deswegen brauchen Sie die Referenzhalter, um das Kunibert-Objekt festzu- halten, wenn der Referenz kunibert das Objekt Kuni- gunde zugewiesen wird. Das ist der Code für die Klasse Elefant in der Datei Elefant.cs, die wir dem Projekt hinzugefügt haben. Vergessen Sie am Anfang des Formulars die »using System. Windows.Forms;«- Zeile nicht. Ohne funktioniert die MessageBox-Anwei- sung nicht. Hier ist der Code für die Klasse Form1 aus Form1.cs. Halten Sie Ihre Referenzen Sie können diese using-Anweisung in die geschweiften Klammern des Na- mensraums stecken, wenn Sie wollen. lösung zur Übung Kopf- nuss
  26. 26. Sie sind hier 4  165 Typen und Referenzen Zwei Referenzen bedeuten ZWEI Möglichkeiten, die Daten eines Objekts zu ändern Elefant-Ob jekt Elefant-O bjekt private void button4_Click(object sender, EventArgs e) { kunibert = kunigunde; kunibert.Ohrengröße = 4321; kunibert.WerBinIch(); } Sie können nicht nur alle Referenzen auf ein Objekt ver- lieren, wenn Sie mehrere Referenzen haben, Sie können ein Objekt auch unbeabsichtigt ändern. Anders gesagt: Eine Referenz auf ein Objekt kann das Objekt ändern, während die andere Referenz auf das Objekt keine ­Ahnung hat, das sich etwas geändert hat. Aufgepasst: Spendieren Sie dem Formular noch einen Button.1 Das ist der Code für diesen Button. Können Sie sich denken, was passiert, wenn Sie darauf klicken?2 Klicken Sie dann auf den neuen Button. Moment mal ... das ist doch die Meldung für Kunigunde! Haben wir nicht die WerBinIch()-Methode von Kunibert aufgerufen? 3 Sie rufen die Methode WerBinIch() auf der Referenz kunibert auf. Das ist die Meldung für Kunigunde. Aber die Ohrengröße haben wir doch per Referenz kunibert gesetzt! Wieso das? Nachdem dieser Code ausgeführt wurde, zeigen kunibert und kunigunde auf das GLEICHE Objekt. kunibert und kunigunde sind jetzt austauschbar. Än- derungen an einer der Referenzen ändern das Objekt, auf das BEIDE zeigen … es gibt keinen Unterschied zwischen kunibert und kunigunde mehr, da beide auf das GLEICHE Objekt zeigen. Aber kunibert zeigt auf das gleiche Ding wie kunigunde. Diese Anweisung setzt die Ohren- größe des Objekts, auf das kunibert verweist, auf 4321. Beachten Sie, dass die Daten NICHT über- schrieben werden – es ändern sich nur die Referenzen. Tun Sie das!
  27. 27. 166  Kapitel 4 Array Eines für viele Ein Sonderfall: Arrays int[] größe; größe = new int[7]; größe[0] = 68; größe[1] = 70; größe[2] = 63; größe[3] = 60; größe[4] = 58; größe[5] = 72; größe[6] = 74; Name Der Typ jedes Elements in diesem Array. Beachten Sie, dass das Array ein Objekt ist, obwohl die 7 Elemente Werttypen sind – wie die auf den ersten beiden Seiten dieses Kapitels. 7 int-Variablen Im Speicher wird das Array als ein Speicherhappen gespei- chert, ­obwohl darin mehrere int-Variablen stecken. Wenn Sie eine Menge Daten des gleichen Typs festhalten müssen, beispiels- weise eine Liste mit Größen oder eine Rotte von Hunden, können Sie das mit einem Array machen. Ein Array zeichnet aus, dass es eine Sammlung von Variablen ist, die als ein Objekt behandelt wird. Über ein Array können Sie mehrere Datenteile speichern und ändern, ohne dass Sie die einzelnen Variab­ len separat nachhalten müssen. Um ein Array zu erzeugen, deklarieren Sie es genau wie jede andere Variable mit einem Namen und einem Typ: bool[] einArray; einArray = new bool[15]; einArray[4] = true; Sie deklarieren ein Array über den Typ plus eckige Klammern. Nutzen Sie die Elemente in einem Array, als wären es gewöhnliche Variablen Wenn Sie ein Array nutzen, müssen Sie zunächst eine Referenzvariable de- klarieren, die auf das Array zeigt. Dann müssen Sie mit new das Array-Objekt erstellen und dabei angeben, wie groß das Array sein soll. Erst dann können Sie die Elemente im Array setzen. Hier ist ein Codebeispiel, das ein Array dekla- riert und füllt – und daneben sehen Sie die Abbildung, die zeigt, was dabei auf dem Heap passiert. Das erste Element des Arrays hat den Index null. Sie hätten die Deklaration der VariableneinArray mit der Initialisierung verbindenkönnen – wie bei jeder anderen Variablen.Dann sähe das so aus:bool[] einArray = new bool[15]; Ein Array wird mit dem Schlüssel-wort new erzeugt, weil es ein Objektist. Eine Array-Variable ist alsoebenfalls eine Referenz­variable. Diese Zeile setzt den Wert des fünften Elements von einArray auf true. Es ist das fünfte, weil das erste einArray[0] ist, das zweite einArray[1] usw. Dieses Array enthält 15 Elemente. Sie referen- zieren die Elemente, aber jedes funktioniert im Prinzip wie eine gewöhnli- che Variable. int int int int int int int Strings und Arrays unterscheiden sich von den anderen Datenty- pen, die Ihnen bisher begegnet sind. Sie sind die einzigen, deren Größe nicht festgelegt ist (denken Sie eine Weile darüber nach).
  28. 28. Sie sind hier 4 167 Typen und Referenzen Hund-O bjekt Hund-O bjekt Ein Array mit Objektreferenzen können Sie auf gleiche Weise erzeugen wie ein Array mit Zahlen oder Strings. Arrays kümmern sich nicht um den Typ der darin gespeicherten Variablen. Der bleibt Ihnen überlassen. Sie können also problemlos ein Array mit ints wie auch ein Array mit Ente-Objekten haben. Hier ist Code, der ein Array mit 7 Hund-Variablen erzeugt. Die Zeile, die ledig- lich das Array initialisiert, erzeugt auch die Referenzvariablen. Da es nur zwei new Hund()-Zeilen gibt, werden auch nur zwei richtige Instanzen der Klasse Hund erstellt. Hund[] hunde = new Hund[7]; hunde[5] = new Hund(); hunde[0] = new Hund(); Arrays können auch einen Haufen Referenzvariablen speichern Diese Zeile deklariert die Variable hunde, die ein Array mit Referenzen auf Hund-Objekte speichert, und erzeugt dann ein Array mit 7 Elementen. Diese beiden Zeilen erzeugen neueInstanzen von Hund und stecken siezu den Indizes 0 und 5. Die beim Setzen oder Abrufen eines Array­ Elements in den eckigen Klammern angegebene Zahl nennt man Index. Das erste Element im Array hat den Index null. Alle Elemente in diesem Array sind Referenzen. Das Array selbst ist ein Objekt. 7 Hund-Variablen Die erste Zeile des Codes hat nur das Array erzeugt, nicht die Instanzen. Das Array ist eine Liste mit 7 Hund- Referenzvariablen. Hund Hund Hund Hund Hund Hund Hund Array Die Länge von Arrays Wie viele Elemente in einem Array stecken, können Sie über seine Length-Eigenschaft ermitteln. Haben Sie ein Array namens größe, können Sie größe.Length verwenden, um seine Länge zu ermitteln. Enthält es 7 Elemente, wird Ihnen 7 gemeldet – das bedeutet, dass die Elemente im Array die Indizes 0 bis 6 tragen.
  29. 29. 168 Kapitel 4 Willkommen beim Sandwich-Discount vom Strammen Max Der Stramme Max hat einen Haufen Fleisch, diverses Brot und mehr Soßen, als man aufzählen kann. Aber was er nicht hat, ist eine Speisekarte! Können Sie ein Programm erstellen, das ihm jeden Tag eine neue zufällige Speisekarte erstellt? Der Stramme Max sagt: »Es ist nicht alt, es ist reif.« Fügen Sie einem neuen Projekt die Klasse MenüMacher hinzu. Zur Herstellung einer Speisekarte benötigen Sie Zutaten. Arrays wären perfekt für diese Listen. Außerdem brauchen wir eine Möglichkeit, zufällig Zutaten auszu- wählen, um diese zu einem Sandwich zu kombinieren. Das .NET Framework bietet die eingebaute Klasse Random, die Zufallszahlen generiert. Unsere Klasse hat also vier Felder: das Feld Zufallszahl mit einer Referenz auf ein Random- Objekt und drei string-Arrays für Fleisch, Soßen und Brot. 1 class MenüMacher { public Random Zufallszahl; string[] Fleisch = { Roastbeef, Salami, Pute, Speck, Braten }; string[] Soßen = { Süßer Senf, Scharfer Senf, Ketchup, Mayo, Aioli, Remoulade }; string[] Brot = { Graubrot, Weißbrot, Toast, Pumpernickel, Ciabatta, Brötchen }; } MenüMacher Zufallszahl Fleisch Soßen Brot MenüEintragHolen() public string MenüEintragHolen() { string zufallsFleisch = Fleisch[Zufallszahl.Next(Fleisch.Length)]; string zufallsSoße = Soßen[Zufallszahl.Next(Soßen.Length)]; string zufallsBrot = Brot[Zufallszahl.Next(Brot.Length)]; return zufallsFleisch + mit + zufallsSoße + auf + zufallsBrot; } Schreiben Sie eine MenüEintragHolen()-Methode, die ein Zufalls- Sandwich erzeugt. Der Zweck der Klasse ist die Zusammenstellung von Sandwiches. Fügen wir also eine entsprechende Methode hinzu. Sie nutzt die Next()-Methode des Random-Objekts, um zufällig Fleisch, Soßen und Brot aus den Arrays auszuwählen. Übergeben Sie Next() einen int-Parameter, liefert die Methode eine Zufallszahl, die kleiner als dieser Parameter ist. Heißt Ihr Random-Objekt Zufallszahl, liefert Zufallszahl.Next(7) also eine Zufallszahl zwischen 0 und 6. Woher wissen wir nun, welchen Parameter wir der Next()-Methode übergeben müssen? Na, das ist einfach – wir übergeben einfach die Length-Eigenschaft der einzelnen Arrays. Diese liefert die Anzahl der Elemente im jeweiligen Array. 2 Die Methode steckt ein beliebiges Element aus dem Array Fleisch in die Variable zufallsFleisch, indem sie der Next()-Methode des Random-Objekts Fleisch.Length übergibt. Das Array Fleisch enthält 5 Elemente. Next(5) liefert also eine Zufalls- zahl zwischen 0 und 4. Das Feld namens Zufalls- zahl hält eine Referenz auf ein Random-Objekt. Ein Aufruf seiner Next()- Methode erzeugt Zufalls- zahlen. Die Klasse hat drei Felder zur Speicherung der drei String-Arrays. Diese nutzt sie, um zufällige Speise- karteneinträge zu erzeugen. Die Methode MenüEintragHolen() liefert einen String, der ein Sandwich enthält, das aus Zufallselementen der drei Arrays gebildet wird. Denken Sie daran, beim Zugriff auf die Array- Elemente eckige Klammern zu verwenden. Der Wert von Brot[2] ist »Toast«. Tun Sie das! Sehen Sie, wie diese Arrays initialisiert werden? Das nennt man einen Collection- Initialisierer. Mehr dazu in Kapitel 8.
  30. 30. Sie sind hier 4  169 Typen und Referenzen Ich speise immer beim Strammen Max!Wie es funktioniert … Fleisch[Zufallszahl.Next(Fleisch.Length)] Fleisch ist ein Array mit Strings. Es enthält fünf Elemente mit den Indizes 0 bis 4. Fleisch[0] entspricht also »Roastbeef«, Fleisch[3] entspricht »Speck«. Die Methode Zufallszahl.Next(7) liefert eine Zufallszahlkleiner 7. Fleisch.Length gibt die Anzahl von Elementen inFleisch zurück. Zufallszahl.Next(Fleisch.Length) liefert Ihnenalso eine Zufallszahl, die größer gleich null, aber kleiner als dieAnzahl von Elementen im Array Fleisch ist. Erstellen Sie Ihr Formular. Fügen Sie dem Formular sechs Labels, label1 bis label6, hinzu. Ergänzen Sie dann Code, der die Text-Eigenschaft jedes Labels über ein MenüMacher-Objekt setzt. Sie müssen das Objekt mit einer neuen Instanz der Klasse Random initialisieren. Hier ist der Code: public Form1() { InitializeComponent(); MenüMacher menü = new MenüMacher() { Zufallszahl = new Random() }; label1.Text = menü.MenüEintragHolen(); label2.Text = menü.MenüEintragHolen(); label3.Text = menü.MenüEintragHolen(); label4.Text = menü.MenüEintragHolen(); label5.Text = menü.MenüEintragHolen(); label6.Text = menü.MenüEintragHolen(); } 3 Initialisieren Sie das Zufallszahl-Feld des MenüMacher- Objekts über einen Objektinitialisierer mit einer neuen ­Instanz der Klasse Random. Jetzt ist alles eingerich- tet, um über die Methode Menü EintragHolen() sechs verschiedene zufällige Sandwiches abzurufen. Bei der Ausführung des Programms zeigen die sechs Labels sechs verschiedene zufällig zusammengestellte Sandwiches. Eine kleine Denkaufgabe: Was geschieht, wenn Sie vergessen, das Feld Zufallszahl zu initialisieren? Wie könnte man das verhindern?
  31. 31. 170 Kapitel 4 Objekte nutzen Referenzen, um zu kommunizieren Bislang haben Sie gesehen, wie Formulare mit Objekten reden, indem Sie auf ihnen Methoden aufrufen oder ihre Eigenschaften abfragen. Über Referenzen können Objekte aber auch unter- einander Methoden aufrufen. Eigentlich kann ein Formular nichts tun, was Objekte nicht auch tun können, weil ein Formular nur ein anderes Objekt ist. Wenn Objekte miteinander reden, ist das Schlüsselwort this nützlich. Jedes Mal, wenn ein Objekt das Schlüsselwort this verwendet, verweist es auf sich selbst – es ist eine Referenz, die auf das Objekt zeigt, die sie nutzt. eine Methode, die einem Elefanten das Sprechen beibringt. Fügen wir der Klasse Elefant eine Methode hinzu. Ihr erster Parameter ist eine Nachricht von einem Elefanten. Der zweite Parameter ist der Elefant, der hier spricht: public void SprichMitMir(string nachricht, Elefant werHierSpricht) { MessageBox.Show(werHierSpricht.Name + sagt: + nachricht); } So sieht es aus, wenn die Methode aufgerufen wird: Elefant kunibert = new Elefant() { Name = Kunibert, Ohrengröße = 81 }; Elefant kunigunde = new Elefant() { Name = Kunigunde, Ohrengröße = 63 }; kunibert.SprichMitMir(Hallo, kunigunde); Wir haben Kuniberts SprichMitMir()-Methode aufgerufen und ihr zwei Parameter übergeben: »Hallo« und eine Referenz auf das Kunigunde-Objekt. Der Parameter werHierSpricht wird genutzt, um auf die Name-Eigenschaft des Elefanten zuzugreifen, der an SprichMitMir() übergeben wurde. 1 eine Methode, die eine andere Methode aufruft. Fügen wir der Klasse Elefant jetzt die Methode SprichMit() hinzu. Sie nutzt ein besonderes Schlüsselwort: this. Das ist eine Referenz, über die ein Objekt über sich selbst reden kann. public void SprichMit(Elefant redeMit, string nachricht) { redeMit.SprichMitMir(nachricht, this); } Schauen wir uns genauer an, wie das funktioniert. kunibert.SprichMit(kunigunde, Hallo); Wird Kuniberts SprichMit()-Methode aufgerufen, nutzt sie den Parameter redeMit (der eine Referenz auf Kunigunde hat), um Kunigundes SprichMitMir()-Methode aufzurufen. redeMit.SprichMitMir(nachricht, this); kunigunde.SprichMitMir(nachricht, [Referenz auf Kunibert]); Das ist, als wäre Kunigunde mit (Hallo, kunibert) aufgerufen worden: 2 Kunibert nutzt redeMit (eine Referenz auf Kunigunde), um SprichMitMir() aufzurufen. this wird durch eine Referenz auf das Kunibert-Objekt ersetzt. Diese Methode von Elefant ruft die SprichtMit()- Methode eines anderen Elefanten auf. Über sie können Elefanten miteinander reden. Ihre Objekte sind Tratschtaschen Elefant Name Ohrengröße WerBinIch() SprichMitMir() SprichMit()
  32. 32. Sie sind hier 4  171 Typen und Referenzen F:Noch mal, bitte – mein Formular ist ein Objekt? A:Ja! Deswegen beginnt Ihr Code mit ei- ner Klassendeklaration. Öffnen Sie den Code für Ihr Formular und schauen Sie ihn sich an. Öffnen Sie dann Program.cs und blicken Sie in die Methode Main() – dort werden Sie »new Form1()« finden. F:Warum sollte ich null verwenden? A:In gewöhnlichen Programmen wird null auf mehrere Weisen verwendet, am häufigsten für Tests: if (kunibert == null) Dieser Test liefert true, wenn die ­kunibert-Referenz auf null gesetzt ist. Außerdem wird das Schlüsselwort null verwendet, wenn man erzwingen will, dass sich der Garbage Collector ein Objekt schnappt. Haben Sie eine Referenz auf ein Objekt, das Sie nicht mehr benötigen, können Sie die Referenz auf null setzen, um es für die Garbage Collection zu markie- ren (es sei denn, es gibt noch eine weitere Referenz darauf). F:Sie reden ständig von der Garbage Collection. Wer sammelt denn da den Müll ein? A:Erinnern Sie sich daran, dass wir Ende des ersten Kapitels von der Common Language Runtime (oder CLR) gesprochen haben? Das ist die virtuelle Maschine, die alle .NET-Programme ausführt. Eine virtuelle Maschine ist ein Mechanismus, über den man laufende Programme vom Rest des Systems isoliert. Unter anderem verwalten virtuelle Maschinen den Speicher, den sie nutzen. Das bedeutet, dass sie alle Ihre Ob- jekte nachhalten, bemerken, wenn die letzte Referenz auf ein Objekt verschwindet, und den Speicher freigeben, den es eingenom- men hat. Wohin noch kein Objekt gekommen ist Es gibt ein weiteres wichtiges Schlüsselwort, das Sie im Zusammenhang mit Objekten verwenden werden. Wenn Sie eine neue Referenz erstellen und diese auf nichts setzen, hat sie dennoch einen Wert. Anfangs ist sie auf null gesetzt. Das heißt, dass sie auf nichts zeigt. Hund-Obje kt2 Hund fido; Hund lucky = new Hund(); fido = new Hund(); Noch gibt es nur ein Objekt. Die fido-Referenz ist auf null gesetzt. Hund-Obje kt1 lucky = null; Hund-Obje kt2 Hund-Obje kt1 Jetzt zeigt fido auf ein Objekt und ist nicht länger null. Setzen wir lucky auf null, zeigt nichts mehr auf das Objekt, das dann Futter für den Garbage Collector wird. Es gibt keine Dummen Fragen
  33. 33. 172  Kapitel 4 F:  Mir ist immer noch nicht ganz klar, wie das mit den Referenzen funktioniert. A:Über Referenzen nutzen Sie die Methoden und Felder eines Objekts. Erzeugen Sie eine Referenz auf ein Hund- Objekt, beispielsweise rex, können Sie diese Referenz nutzen, um auf Methoden zuzugreifen, die Sie für das Hund-Objekt erstellt haben. Haben Sie (nicht statische) Methoden namens Hund.Bellen() oder Hund.Betteln(), können Sie auf diese über die Referenz rex zugreifen, indem Sie rex.Bellen() oder rex. Betteln() verwenden. Sie könnten über die Referenz auch Informationen in den Feldern des Objekts ändern. Über rex. Rasse könnten Sie beispielsweise das Feld Rasse ändern. F:Moment. Heißt das nicht, dass ich, wenn ich einen Wert über eine Referenz ändere, diesen auch für alle anderen Referenzen auf dieses Objekt ändere? A:Ja. Ist hasso eine Referenz auf das gleiche Objekt wie rex, würde eine Änderung von hasso.Rasse in »Beagle« auch rex.Rasse in »Beagle« ändern. F:Das mit den Typen, die Werte unter- schiedlicher Größen aufnehmen, verstehe ich noch nicht. Was bringt das? A:Gut. Die Sache ist, dass Variablen Ihren Zahlen eine Größe zuweisen, die von der tatsächlichen Zahl unabhängig ist. Geben Sie einer Variablen den Typ long, reserviert die CLR, auch wenn die Zahl sehr klein ist (5 beispielsweise), so viel Speicher, wie für den größten möglichen long-Wert erforderlich ist. Und das ist vernünftig, weil sich Variablen ändern und andere Werte annehmen können. Die CLR geht davon aus, dass Sie wissen, was Sie tun, und einer Variablen keinen Typ geben, den sie nicht braucht. Selbst wenn die Zahl jetzt nicht groß ist, kann sie das nach einigen Berechnungen werden, und die CLR reserviert hinreichend Speicher, um damit klarzukommen. F:Sagen Sie mir noch einmal, was dieses »this« macht? A:this ist eine spezielle Variable, die Sie nur in einem Objekt verwenden können. In einer Klasse nutzen Sie this, um auf ein Feld oder eine Methode dieser speziellen Instanz zu verweisen. Das ist besonders nütz- lich, wenn Sie mit einer Klasse arbeiten, deren ­Methoden Methoden anderer Klassen aufru- fen. Ein Objekt kann es nutzen, um eine Re- ferenz auf sich selbst an ein anderes ­Objekt zu senden. Ruft rex eine von hassos Methoden mit this als Parameter auf, gibt er hasso eine Referenz auf rex. Dies und das Code in einer Klasse, von der Objekte instantiiert werden sollen, kann das Schlüsselwort this als Referenz auf die aktuelle Instanz verwenden. ¢¢ Bei der Deklaration einer Variablen wird IMMER ein Typ angegeben. Die Deklaration kann mit der Initialisierung kombiniert werden. ¢¢ Es gibt Werttypen für Zahlen, die Zahlen unterschied- licher Größe aufnehmen. Der größte Ganzzahltyp ist long und der kleinste byte (bis 255). ¢¢ Werttypen haben eine Größe. Werte größerer Typen können nicht in Variablen kleinerer Typen gesteckt wer- den, egal wie groß die Daten tatsächlich sind. ¢¢ Bei literalen Werten gibt das Suffix F einen float (15.6F) und das Suffix M einen decimal (36.12M) an. ¢¢ Einige Typen kann der Compiler automatisch umwandeln (z. B. short in int). Verhindert der Compiler, dass Sie eine Variable auf einen Wert eines anderen Typs setzen, müssen Sie einen Cast (eine Umwandlung) verwenden. ¢¢ Die Sprache reserviert einige Wörter, die Sie nicht für die Namen von Variablen nehmen dürfen. Das sind Wörter wie for, while, using, new und andere, die in der Sprache eine besondere Bedeutung haben. ¢¢ Referenzen sind wie Etiketten. An ein Objekt können Sie so viele heften, wie Sie möchten. ¢¢ Gibt es auf ein Objekt keine Referenz mehr, kommt der Garbage Collector. Es gibt keine Dummen Fragen Punkt für Punkt Es gibt einen speziellen Fall, in dem Sie keinen Typ deklarieren müssen – mehr dazu erfahren Sie bei der Behandlung des Schlüsselworts »var« in Kapitel 14.
  34. 34. Sie sind hier 4  173 Typen und Referenzen Hier sind ein Array mit Elefant-Objekten und eine Schleife, die alle durchläuft und den mit den größten Ohren sucht. Geben Sie den Wert von größteOhren.Ohrengröße nach jedem Durchlauf der for-Schleife an. Durchlauf 1 größteOhren.Ohrengröße = _________ Durchlauf 2 größteOhren.Ohrengröße = _________ Durchlauf 3 größteOhren.Ohrengröße = _________ Durchlauf 4 größteOhren.Ohrengröße = _________ Durchlauf 5 größteOhren.Ohrengröße = _________ Durchlauf 6 größteOhren.Ohrengröße = _________ private void button1_Click(object sender, EventArgs e) { Elefant[] elefanten = new Elefant[7]; elefanten[0] = new Elefant() { Name = Kunibert, Ohrengröße = 81 }; elefanten[1] = new Elefant() { Name = Kunigunde, Ohrengröße = 63 }; elefanten[2] = new Elefant() { Name = Lukas, Ohrengröße = 84 }; elefanten[3] = new Elefant() { Name = Lucille, Ohrengröße = 61 }; elefanten[4] = new Elefant() { Name = Lothar, Ohrengröße = 88 }; elefanten[5] = new Elefant() { Name = Linda, Ohrengröße = 67 }; elefanten[6] = new Elefant() { Name = Hubert, Ohrengröße = 89 }; Elefant größteOhren = elefanten[0]; for (int i = 1; i elefanten.Length; i++) { if (elefanten[i].Ohrengröße größteOhren.Ohrengröße) { größteOhren = elefanten[i]; } } MessageBox.Show(größteOhren.Ohrengröße.ToString()); } Vorsicht – diese Schleife beginnt mit dem zweiten Element des Arrays (bei Index 1) und läuft sechs Mal, bis i gleich der Länge des Arrays ist. Wir erzeugen ein Array mit 7 Elefant-Referenzen. Jedes Array beginnt mit dem Index 0. Der erste Elefant im Array ist also elefanten[0]. Diese Zeile lässt die Referenz größteOhren auf den Elefanten zeigen, auf den elefanten[i] zeigt. Lösung auf Seite 184. Spitzen Sie Ihren Bleistift
  35. 35. 174 Kapitel 4 refNum = index[y]; int y = 0; String ergebnis = ; MessageBox.Show(ergebnis); y = y + 1; index[0] = 1; index[1] = 3; index[2] = 0; index[3] = 2; ergebnis += inseln[refNum]; int[] index = new int[4]; ergebnis += nInsel = ; String[] inseln = new String[4]; int refNum; while (y 4) { private void button1_Click (object sender, EventArgs e){ refNum = index[y]; int refNum; inseln[0] = Bermuda;inseln[1] = Fidschi;inseln[2] = Azoren;inseln[3] = Kuba; } Code­Magneten Der Code für einen Button ist völlig durcheinandergeraten. Können Sie die Schnipsel so zusammensetzen, dass sie eine funktionierende Methode ergeben, die die unten gezeigte Ausgabe erzeugt? } Lösung auf Seite 185. Code-Magneten und Pool-Puzzle
  36. 36. Sie sind hier 4  175 Typen und Referenzen class Dreieck { double Fläche; int Höhe; int Breite; public static void Main(String[] args) { string ergebnisse = ; __________ ___________________________ while ( ________ ) { _________________________ _____.Höhe = (x + 1) * 2; _____.Breite = x + 4; __________________ ergebnisse += Dreieck + x + , Fläche; ergebnisse += = + _____.Fläche + n; ___________ } ___________ x = 27; Dreieck d5 = dA[2]; dA[2].Fläche = 343; ergebnisse += y = + y; MessageBox.Show(ergebnisse + , d5 Fläche = + d5.Fläche); } void FlächeSetzen() { ____________ = (Höhe * Breite) / 2; } } Ausgabe Bonusfrage! Zusatzpunkte gibt es, wenn es Ihnen gelingt, die beiden in der Ausgabe verbleibenden Lücken mit Schnipseln aus dem Pool zu füllen. Hier ist der Einstiegspunkt für die Anwendung. Nehmen Sie an, sie steht in einer Datei mit den erforderlichen »using«-Zeilen. x = x + 1; x = x + 2; x = x - 1; x 4 x 5 Dreieck [ ] dA = new Dreieck(4); Dreieck dA = new [ ] Dreieck[4]; Dreieck [ ] dA = new Dreieck[4]; dA = new Dreieck(); dA[x] = new Dreieck(); dA.x = new Dreieck(); dA[x] = FlächeSetzen(); dA.x = FlächeSetzen(); dA[x].FlächeSetzen(); int x; int y; int x = 0; int x = 1; int y = x; Fläche dA.Fläche dA.x.Fläche dA[x].Fläche dA.x dA(x) dA[x] x y 28 30.0 4, d5 Fläche = 18 4, d5 Fläche = 343 27, d5 Fläche = 18 27, d5 Fläche = 343 Tipp: FlächeSetzen() ist NICHT statisch. Schauen Sie in Kapitel 3 nach, wenn Sie eine Auffrischung zum Schlüsselwort static brauchen. Hinweis: Jeder Schnip- sel aus dem Pool kann mehrfach verwendet werden. Pool-Puzzle Sie haben die Aufgabe, die leeren ­Zeilen im Code mit den Code- schnipseln aus dem Pool zu füllen. Einzelne Schnipsel können mehrfach verwendet werden, und Sie werden nicht alle Schnipsel benötigen. Das Ziel ist es, eine Klasse zu erstel- len, die sich kompilieren lässt und die gezeigte Ausgabe erzeugt. Lösung auf Seite 186.
  37. 37. 176 Kapitel 4 Etwas Vergnügliches aufbauen Erstellen Sie ein Tippspiel Sie haben einen entscheidenden Punkt erreicht ... und wissen jetzt genug, um ein Spiel aufzubauen! Und so soll es funktionieren. Das Formular zeigt zufällig Buchstaben an. Tippt der Spieler auf einen dieser Buchstaben, verschwindet der Buchstabe, und die Trefferquote steigt. Tippt der Spieler auf einen falschen Buchstaben, sinkt die Treffer- quote. Mit der Zeit läuft das Spiel kontinuierlich schneller und wird mit jedem richtigen Buchstaben schwerer. Ist das ganze Formular mit Buchstaben gefüllt, endet das Spiel! Tun Sie das! Erstellen Sie das Formular. So soll das Formular im Formular-Designer aussehen: 1 Dazu müssen Sie Folgendes tun: ≥ Schalten Sie die Minimieren- und Maximieren-Symbole ab. Setzen Sie dann die FormBorderStyle- Eigenschaft auf Fixed3D. Das verhindert, dass der Spieler das Formular versehentlich verschiebt oder ver- ändert. Verändern Sie die Größe, sodass es erheblich breiter als hoch ist (unseres hat die Größe 876 x 174). ≥ Ziehen Sie aus dem Werkzeugkasten eine ListBox auf das Formular. Setzen Sie ihre Dock-Eigenschaft auf Fill und ihre MultiColumn-Eigenschaft auf true. Wählen Sie für Font 72 Punkte fett. ≥ Klappen Sie oben im Werkzeugkasten die Gruppe »Alle Windows Forms« auf. Jetzt haben Sie Zugriff auf eine Menge Steuerelemente. Suchen Sie nach Timer und klicken Sie doppelt darauf, um es dem Formular hinzuzufügen. ≥ Suchen Sie nach StatusStrip und klicken Sie auch darauf doppelt, um Ihrem Formular eine Statusleiste hinzuzufügen. Jetzt sollten Sie die StatusStrip- und Timer-Symbole im grauen Bereich unten im Formular-Designer sehen: Erkennen Sie, wie man Timer einsetzen kann, um ein Formular mehrere Dinge gleichzeitig machen zu lassen? Nehmen Sie sich einen Augenblick Zeit, gehen Sie zu Punkt 3 in Anhang A und ma- chen Sie sich mit einem anderen Mittel vertraut, um das zu erreichen.
  38. 38. Sie sind hier 4  177 Typen und Referenzen Sie benötigen drei neue Steuer­ elemente, mit denen sich aber sehr leicht arbei- ten lässt! Obwohl Ihnen ListBox, StatusStrip und Timer noch nicht begegnet sind, wissen Sie bereits, wie man ihre Eigenschaften setzt und wie man mit ihnen im Code arbeitet. In den folgenden Kapiteln werden Sie noch einiges über sie lernen. Richten Sie den Timer ein. Ist Ihnen aufgefallen, dass der Timer nicht in Ihrem Formular erscheint? Das liegt daran, dass er ein unsichtbares Steuerelement ist: Er hat keinen Einfluss auf das Aussehen des Formulars, sondern macht lediglich eine einzige Sache: Er ruft immer wieder eine Methode auf. Setzen Sie seine Inter- val-Eigenschaft auf 800, damit diese Methode alle 800 Millisekunden aufgerufen wird. Klicken Sie anschließend doppelt auf das timer1-Symbol im Designer. Die IDE macht dann, was sie immer tut, wenn Sie doppelt auf ein Steuerelement klicken: Sie fügt Ihrem Formular eine Methode hinzu. Diese erhält den Namen timer1_Tick, und hier ist der Code dafür: 3 private void timer1_Tick(object sender, EventArgs e) { // Der ListBox zufällig ein Zeichen hinzufügen. listBox1.Items.Add((Keys)random.Next(65, 90)); if (listBox1.Items.Count 7) { listBox1.Items.Clear(); listBox1.Items.Add(Game Over); timer1.Stop(); } } Richten Sie den StatusStrip ein. Schauen Sie sich die Statusleiste in der Abbildung genau an. Auf der einen Seite befinden sich einige Labels: 2 Auf der anderen sehen Sie ein Label und eine Fortschritts- leiste: Fügen Sie dem StatusStrip ein StatusLabel hinzu, indem Sie auf sein Menü klicken und Status- Label wählen. Tun Sie dann Folgendes: ≥≥ Nutzen Sie das Eigenschaften-Fenster, um (Name) auf richtigLabel und Text auf »Richtig: 0« zu setzen. Fügen Sie drei weitere StatusLabel hinzu: falschLabel, gesamtLabel und trefferquoteLabel. Setzen Sie ihre Text- Eigenschaft auf Fehler: 0, Gesamt: 0 bzw. Trefferquote: 0. ≥≥ Fügen Sie noch ein weiteres StatusLabel ein und setzen Sie Spring auf True, TextAlign auf MiddleRight und Text auf »Schwierigkeit«. Fügen Sie abschließend eine ProgressBar hinzu, nennen Sie sie schwie- rigkeitProgressBar und setzen Sie Maximum auf 800. ≥≥ Setzen Sie die SizingGrip-Eigenschaft des ­StatusStrip auf False (drücken Sie auf Escape, wenn Sie ein StatusLabel oder eine ProgressBar ausgewählt haben, um den Fokus der IDE wieder auf den übergeordneten StatusStrip zurückzusetzen). Sie werden gleich ein Feld namens »random« hinzufügen. Haben Sie eine Idee, welchen Typ es haben wird? Die Klasse Timer hat eine Start()-Methode,aber diese müssen Sie für dieses Projekt nichtaufrufen. Stattdessen setzen Sie die EigenschaftEnabled auf True, die ihn automatisch startet. Entspannen Sie sich Entspannen Sie sich
  39. 39. 178 Kapitel 4 Der Schlüssel zu einem guten Spiel Schreiben Sie eine Klasse, die die Spielstatistik modelliert. Wenn das Formular anzeigen soll, wie viele Tasten der Spieler insgesamt drückte, wie viele er davon richtig hatte und wie viele falsch, sowie seine Trefferquote, müssen wir alle diese Daten nachhalten. Klingt nach einer Aufgabe für eine neue Klasse! Fügen Sie Ihrem Projekt eine Klasse namens Statistik mit vier int-Feldern namens Gesamt, Falsch, Richtig und Trefferquote sowie eine Methode namens Aktualisieren hinzu, die einen bool-Parameter erwartet (true, wenn ein richtiger Buchstabe getippt wurde, und andernfalls false). 4 Statistik Gesamt Falsch Richtig Trefferquote Aktualisieren() class Statistik { public int Gesamt = 0; public int Falsch = 0; public int Richtig = 0; public int Trefferquote = 0; public void Aktualisieren(bool richtigeTaste) { Gesamt++; if (!richtigeTaste) { Falsch++; } else { Richtig++; } Trefferquote = 100 * Richtig / Gesamt; } } Immer wenn die Methode Aktualisieren() aufgerufen wird, wird die Trefferquote neu berechnet. Fügen Sie Ihrem Formular Felder für ein Statistik- und ein Random-Objekt hinzu und starten Sie den Timer. Sie brauchen eine Instanz der neuen Klasse Statistik, um die Daten zu speichern. Fügen Sie also ein statistik-Feld hinzu. Und Sie haben bereits gesehen, dass Sie ein Feld namens ran- dom benötigen, das ein Random-Objekt festhält. Fügen Sie oben im Formular die beiden Felder ein: public partial class Form1 : Form { Random random = new Random(); Statistik statistik = new Statistik(); ... 5 Bevor Sie fortfahren, müssen Sie drei Eigenschaften setzen: die Enabled- Eigenschaft des Timers auf true, die Maximum-Eigenschaft der ProgressBar auf 701 und die KeyPreview-Eigenschaft des Formulars auf true. Überlegen Sie einen Augenblick, warum Sie diese Eigenschaf- ten benötigen. Was geschieht, wenn Sie sie nicht setzen?
  40. 40. Sie sind hier 4  179 Typen und Referenzen Die Tastenaktionen müssen verarbeitet werden. Um eine Sache müssen wir uns noch kümmern: Wenn der Spieler eine Taste drückt, muss geprüft werden, ob die Taste richtig ist (gegebenenfalls wird dann der Buchstabe aus der ListBox entfernt). Anschließend müssen die Daten im StatusStrip aktualisiert werden. 6 private void listBox1_KeyDown(object sender, KeyEventArgs e) { // Wurde eine richtige Taste gedrückt, wird das Zeichen entfernt // und das Spiel etwas schneller gemacht. if (listBox1.Items.Contains(e.KeyCode)) { listBox1.Items.Remove(e.KeyCode); listBox1.Refresh(); if (timer1.Interval 400) timer1.Interval -= 10; if (timer1.Interval 250) timer1.Interval -= 7; if (timer1.Interval 100) timer1.Interval -= 2; schwierigkeitProgressBar.Value = 800 - timer1.Interval; // Richtige Taste gedrückt, also das Statistik-Objekt aktualisieren, // indem Aktualisieren() mit dem Argument true aufgerufen wird. statistik.Aktualisieren(true); } else { // Falsche Taste gedrückt, also das Statistik-Objekt aktualisieren, // indem Aktualisieren() mit dem Argument false aufgerufen wird. statistik.Aktualisieren(false); } // Die Labels im StatusStrip aktualisieren. richtigLabel.Text = Richtig: + statistik.Richtig; falschLabel.Text = Falsch: + statistik.Falsch; gesamtLabel.Text = Gesamt: + statistik.Gesamt; trefferquoteLabel.Text = Trefferquote: + statistik.Trefferquote + %; } Starten Sie Ihr Spiel. Das Spiel ist fertig! Starten Sie es und schauen Sie, wie gut Sie Ihre Arbeit gemacht haben. Eventuell müssen Sie die Schriftgröße der ListBox ändern, damit sie genau 7 Zeichen aufnimmt. Außerdem können Sie die Schwierigkeit anpassen, indem Sie die Werte ändern, die in der Methode listBox1_KeyDown() von timer1.Interval abgezogen werden. 7 Dieser Teil erhöht die Schwierigkeit, wenn der Spieler mehr Tasten richtig drückte. Sie können das Spiel vereinfachen, indem Sie die Beträge reduzieren, die von timer1.Interval abgezogen werden, oder erschweren, indem Sie sie erhöhen. Diese if-Anweisung prüft, ob die ListBox das Zeichen enthält, das gedrückt wurde. Ist das der Fall, wird es aus der ListBox entfernt, und die Schwierigkeit des Spiels wird erhöht. Wird eine Taste gedrückt, ruft ­listBox1_Key- Down() die Aktua­- lisieren()-Methode des Statistik- Objekts auf, um die Statistik zu aktualisieren, und zeigt sie dann im StatusStrip an. Aktivieren Sie im Formular-Designer die ListBox. Klicken Sie auf den Blitz im Fenster Eigenschaften. Gehen Sie zur Zeile KeyDown und klicken Sie doppelt darauf. Das weist die IDE an, eine Me- thode listBox1_KeyDown() zu erstellen, die aufgerufen wird, wenn eine Taste gedrückt wird. Hier ist der Code für die Methode: Klicken Sie auf dieses Symbol, um die Ansicht zu ändern. Der Button links davon stellt die ursprüngliche Ansicht wieder her. Was Sie dann sehen, sind Ereignisse. Über diese werden Sie bald einiges mehr erfahren. Das Spiel läuft nur einmal. Wie können Sie es so ändern, dass der Spieler ein neues Spiel starten kann, wenn »Game Over« angezeigt wird?
  41. 41. 180  Kapitel 4 Lenken Sie Ihre Steuerelemente Steuerelemente sind ganz gewöhnliche Objekte Sie haben jede Menge Formulare aufgebaut, indem Sie Steuerelemente aus der Toolbox herausgezogen haben. Doch diese Steuerelemente sind eigentlich ganz gewöhnliche Objekte. Da es Objekte sind, können Sie Referen- zen darauf erhalten und mit ihnen arbeiten wie mit den Instanzen einer Klasse, die Sie selbst geschrieben haben. Schauen wir uns ein Beispiel dafür an, indem wir ein Programm erstellen, das Label-Steuerelemente animiert und im Formular hin- und herspringen lässt. using System.Windows.Forms; class LabelAnimator { public Label DasLabel; public bool Vorwärts = true; public void Bewegen() { if (DasLabel != null) { if (Vorwärts == true) { DasLabel.Left += 5; if (DasLabel.Left = DasLabel.Parent.Width - DasLabel.Width) { Vorwärts = false; } } else { DasLabel.Left -= 5; if (DasLabel.Left = 0) { Vorwärts = true; } } } } } Erstellen Sie eine neue Windows Forms-­ Anwendung und bauen Sie dieses Formular auf. 1 Diese Klasse hat ein Feld namens DasLabel, das den Typ Label hat, folglich also eine Referenz auf ein Label-Objekt festhält. Wie alle Referenzen ist das Feld zunächst null. Es wird auf eins der Labels auf dem Formular gesetzt. Sie brauchen diese »using«- Zeile, weil sich Label in diesem Namensraum befindet. Schreiben Sie eine Klasse namens ­LabelAnimator. Hier ist der Code dafür: 2 Ziehen Sie drei Labels und drei Buttons auf das Formu- lar. Klicken Sie doppelt auf jeden der Buttons, um einen Event-Handler für jeden davon einzufügen. Ziehen Sie einen Timer auf das Formular und nutzen Sie das Eigenschaften-Fenster, um seine Enabled-­ Eigenschaft auf True und seine Interval-Eigen- schaft auf 1 zu setzen. Klicken Sie dann doppelt darauf, um den timer1_Tick()-Event-Handler zu erzeugen. Dieser Boolesche Wert wird permanent von wahr in falsch umgeschaltet, während sich das Label über das Formular bewegt. Wenn Sie ein Label über das Formular bewegen wollen, müssen Sie eine neue Instanz der Klasse LabelAni- mator erstellen, ihr DasLabel-Feld auf ein Label- Steuerelement auf dem Formular setzen und dann immer wieder seine Bewegen()-Methode aufrufen. Bei jedem Aufruf von Bewegen() verschiebt Label­ Animator das Label, indem die Eigenschaft Left ge- ändert wird. Wenn das Feld Vorwärts wahr ist, wird das Label nach rechts bewegt, indem der Eigenschaft 5 hinzugefügt wird, andernfalls wird es nach links bewegt, indem von ihr 5 abgezogen wird. Jedes Steuerelement hat eine Parent-Eigenschaft, die eine Referenz auf das Formular enthält, weil auch das Formular ein Objekt ist! Tun Sie das! Die Methode Bewegen() ermittelt, ob das Label den rechten Rand des Formulars erreicht hat, indem sie mit = prüft, ob die Eigenschaft Left größer oder gleich der Breite des Formulars ist. Wenn Sie ein Steuerelement über ein Formular ziehen, setzt die IDE die Eigenschaften Top und Left. Ihre Programme können diese Eigenschaften nutzen, um Steuerelemente über das Formular zu bewegen. Warum ziehen wir die Breite des Labels von der Breite des Formulars ab?
  42. 42. Sie sind hier 4  181 Typen und Referenzen public partial class Form1 : Form { public Form1() { InitializeComponent(); } LabelAnimator[] animatoren = new LabelAnimator[3]; private void AnimationAnAus(int index, Label animator) { if (animatoren[index] == null) { animatoren[index] = new LabelAnimator(); animatoren[index].DasLabel = animator; } else { animatoren[index] = null; } } private void button1_Click(object sender, EventArgs e) { AnimationAnAus(0, label1); } private void button2_Click(object sender, EventArgs e) { AnimationAnAus(1, label2); } private void button3_Click(object sender, EventArgs e) { AnimationAnAus(2, label3); } private void timer1_Tick(object sender, EventArgs e) { for (int i = 0; i 3; i++) { if (animatoren[i] != null) { animatoren[i].Bewegen(); } } } } Hier ist der Code des Formulars. Schauen Sie, ob Sie herausfinden können, was hier ge- schieht. Er nutzt ein Array mit LabelAnimator-Objekten, um die Label hin- und herzubewe- gen, und der Timer-Tick-Event-Handler ruft immer wieder ihre Bewegen()-Methode auf. 3 Klicken Sie auf button1, um label1 in Bewegung zu versetzen. Klicken Sie erneut darauf, um die Bewegung zu beenden. Die beiden anderen Buttons steuern die beiden anderen Labels. Die Labels bewegen sich zwischen den Rändern des Formulars hin und her – auch dann, wenn Sie es schmaler oder breiter machen. Da Steuerele­ mente Objekte sind, können Sie Referenzen da­ rauf als Metho­ denparameter übergeben und in Arrays, Fel­ dern und Vari­ ablen speichern. Alle Buttons rufen die Methode Anima- tionAnAus() auf und übergeben einen Index eines Arrays und eine Referenz auf eins der Labels auf dem Formular. Das Formular speichert ein Array mit LabelAnimator- Referenzen in einem Feld namens animatoren. Wenn die AnimationAnAus()-Methode aufgerufen wird, nutzt sie den Parameter index, um ein Element des Arrays zu prüfen. Ist das Element null, erzeugt sie ein neues LabelAnimator-Ob- jekt und speichert seine Referenz im Array. Andernfalls wird das Element gelöscht, indem die Referenz auf null gesetzt wird. Der Timer nutzt eine for- Schleife, um die Bewegen()- Methode der LabelAnimator- Objekte aufzurufen, wenn die Referenz nicht null ist. Wird das Element auf null gesetzt, wird die Bewegung auf dem Formular abgestellt. Verstehen Sie, was mit den Button- Event-Hand- lern passiert? Sie müssen herausfinden, wie Sie die Bewegung der Labels an- und abschalten.
  43. 43. 182  Kapitel 4 In C# gibt es ungefähr 77 reservierte Wörter, die als Schlüsselwörter bezeichnet werden. Diese Wörter werden durch den C#-Compiler reserviert und dürfen nicht als Variablennamen verwendet werden. Wenn Sie mit dem Buch durch sind, werden Sie sie alle gut kennen. Hier sind einige, die Sie schon benutzt haben. Schreiben Sie, was Ihrer Meinung nach diese Wörter in C# tun. namespace for class public else new using if while Namensräume sichern, dass die Namen, die Sie in Ihren Programmen verwenden, nicht mit denen im .NET Framework oder anderen in Ihrem Programm verwendeten externen Klassen kollidieren. Alle Klassen und Methoden in einem Programm sind in einem Namensraum. Eine Schleife auf Basis von drei Ausdrücken. Im ersten wird die verwendete Variable deklariert, die dann im zweiten anhand einer Testbedingung geprüft wird. Die dritte Anweisung macht etwas mit dem Wert. In einer Klasse definieren Sie ein Objekt. Klassen haben Eigenschaften und Methoden. Eigenschaften sind das, was eine Klasse weiß, Methoden sind das, was eine Klasse tut. Eine öffentliche Klasse kann von jeder anderen Klasse im Projekt verwendet werden. Öffentliche Methoden und Eigenschaften können außerhalb der Klasse genutzt werden, in der sie deklariert werden. Code, der mit else beginnt, wird ausgeführt, wenn die dazugehörige if-Anweisung fehlschlägt. Wird verwendet, um eine neue Instanz einer Klasse zu erstellen. Damit werden alle Namensräume aufgeführt, die in einem Programm verwendet werden. using ermöglicht Ihnen, Code aus dem .NET Framework und anderen vordefinierten Klassen anderer Hersteller sowie aus Klassen zu verwenden, die Sie selbst geschrieben haben. Eine Möglichkeit, in einem Programm eine Bedingungsanweisung einzurichten. Sie sagt, dass eine Gruppe von Anweisungen ausgeführt werden soll, wenn eine Testbedingung wahr ist, und eine andere, wenn sie nicht wahr ist. while-Schleifen sind Schleifen, die ausgeführt werden, solange ihre Testbedingung wahr ist. lösung zur Übung Lösungen zu den Übungen
  44. 44. Sie sind hier 4  183 Typen und Referenzen Typ-Kreuzworträtsel, Lösung R 1 U 2 D 3 O 4 U B L E M B S W N 5 V 6 J E A A E 7 S C A P E R N M R C V D W 8 E R 9 T I T 10 Y P I E U 11 E C 12 H A R E L N F A B T 13 O S T R I N G S E S L T I V 14 E R K E T T E N Z 15 U W E I S U N G E I N N N E Z G 16 A R B A G E D Waagerecht 3. Der Typ, der die größten Zahlen speichern kann. [DOUBLE] 7. n und r sind _____-Sequenzen. [ESCAPE] 8. Wird das für eine Variable nicht gesetzt, lässt sich Ihr Programm nicht kompilieren. [WERT] 10. Die Deklaration einer Variablen beginnt immer damit. [TYP] 12. Der Typ, der nur ein einzelnes Zeichen speichert. [CHAR] 13. Jedes Objekt hat diese Methode, die es in einen String umwandelt. [TOSTRING] 14. Das tun Sie, wenn Sie mit dem +-Operator zwei Strings zusammenkleben. [VERKETTEN] 15. Die Deklaration und die ____________ einer Variablen können zu einer Anweisung zusammengefasst werden. [ZUWEISUNG] Senkrecht 1. »namespace«, »for«, »while«, »using« und »new« sind alles Beispiele für _____________ Wörter. [RESERVIERTE] 2. Das machen die arithmetischen Operatoren für Sie mit Typen automatisch. [UMWANDELN] 4. Einer Variablen dieses Typs können Sie jeden Wert zuweisen. [OBJECT] 5. Der zweite Teil einer Variablendeklaration. [NAME] 6. Was Ihr Programm nutzt, um mit Daten zu arbeiten, die im Speicher sind. [VARIABLE] 9. Eine Variable, die auf ein Objekt zeigt. [REFERENZ] 11. Die vier Typen für ganze Zahlen, die nur positive Zahlen speichern. [UNSIGNED] 12. Das, was (int) in folgender Codezeile macht: x = (int) y; [CASTING]
  45. 45. 184  Kapitel 4 private void button1_Click(object sender, EventArgs e) { Elefant[] elefanten = new Elefant[7]; elefanten[0] = new Elefant() { Name = Kunibert, Ohrengröße = 81 }; elefanten[1] = new Elefant() { Name = Kunigunde, Ohrengröße = 63 }; elefanten[2] = new Elefant() { Name = Lukas, Ohrengröße = 84 }; elefanten[3] = new Elefant() { Name = Lucille, Ohrengröße = 61 }; elefanten[4] = new Elefant() { Name = Lothar, Ohrengröße = 88 }; elefanten[5] = new Elefant() { Name = Linda, Ohrengröße = 67 }; elefanten[6] = new Elefant() { Name = Hubert, Ohrengröße = 89 }; Elefant größteOhren = elefanten[0]; for (int i = 1; i elefanten.Length; i++) { if (elefanten[i].Ohrengröße größteOhren.Ohrengröße) { größteOhren = elefanten[i]; } } MessageBox.Show(größteOhren.Ohrengröße.ToString()); } Durchlauf 1 größteOhren.Ohrengröße = _________ Durchlauf 2 größteOhren.Ohrengröße = _________ Durchlauf 3 größteOhren.Ohrengröße = _________ Durchlauf 4 größteOhren.Ohrengröße = _________ Durchlauf 5 größteOhren.Ohrengröße = _________ Durchlauf 6 größteOhren.Ohrengröße = _________ Lösungen zu den Übungen 81 84 84 88 88 89 Haben Sie daran gedacht, dass die Schleife mit dem zweiten Element des Arrays be- ginnt? ­Warum ist das wohl so? größteOhren hält das Element fest, das beiden bisherigen Schleifendurchläufen als dasmit den größten Ohren erkannt wurde. Die for-Schleife beginnt mit dem zweiten Elefanten und vergleicht ihn mit dem Elefanten, auf den größteOhren zeigt. Sind seine Ohren größer, lässt sie größteOhren stattdessen auf diesen Elefanten zeigen. Dann geht sie zum nächsten weiter und wieder zum nächsten … am Ende der Schleife zeigt größteOhren auf den Elefanten mit den größten Ohren. Hier sind ein Array mit Elefant-Objekten und eine Schleife, die alle durchläuft und den mit den größten Ohren sucht. Sie sollten den Wert von größteOhren.Ohrengröße nach jedem Durch- lauf der for-Schleife angeben. Prüfen Sie das mit dem Debugger! Setzen Sie hier den Unterbrechungspunkt und über- wachen Sie größteOhren.Ohrengröße. Lösung Spitzen Sie Ihren Bleistift
  46. 46. Sie sind hier 4 185 Code­Magneten, Lösung Der Code für einen Button ist völlig durcheinandergeraten. Konnten Sie die Schnipsel so zusammensetzen, dass sie eine funktionierende Methode ergeben, die die unten gezeigte Ausgabe erzeugt? private void button1_Click (object sender, EventArgs e){ String ergebnis = ; int[] index = new int[4]; int[] index = new int[4]; index[0] = 1; index[1] = 3; index[2] = 0; index[3] = 2; inseln[0] = Bermuda; inseln[1] = Fidschi; inseln[2] = Azoren; inseln[3] = Kuba; index[3] = 2; inseln[0] = Bermuda; String[] inseln = new String[4]; inseln[3] = Kuba; int y = 0; int refNum; while (y 4) { refNum = index[y];refNum = index[y]; ergebnis += nInsel = ; ergebnis += nInsel = ; ergebnis += inseln[refNum]; y = y + 1; } } MessageBox.Show(ergebnis); Der String ergebnis wird aufgebaut, indem die Zeilen mit dem +=-Operator aneinandergehängt werden. Diese while-Schleifezieht einen Wert ausdem Array index[]und nutzt ihn als Indexim Array inseln[]. Hier wird das Array inseln[] initialisiert. Hier wird das Array index[] initialisiert. Typen und Referenzen

×