Einführung in die Programmiersprache C# Kapitel 1: C# Übersicht
Transcrição
Einführung in die Programmiersprache C# Kapitel 1: C# Übersicht
C# und .NET: die Entwicklung Einführung in die Programmiersprache C# Datum Ereignis Juni 2000 Bill Gates stellt erstmals die .NET-„Vision“ vor. Oktober 2000 C# wird zur Standardisierung eingereicht Januar 2002 .NET 1.0 und Visual Studio .NET 2002 werden veröffentlicht April 2003 .NET 1.1und Visual Studio 2003 werden veröffentlicht November 2005 .NET 2.0 und Visual Studio 2005 werden veröffentlicht November 2006 .NET 3.0 wird veröffentlich November 2007 .NET 3.5 und Visual Studio 2008 werden veröffentlicht Rainer Schmidberger [email protected] se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH se-rt C# 1.01 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Folie 3 C# 1.01 .NET: Framework, Sprachen und Werkzeuge VB C++ C# JScript … Common Language Specification Web Services Entwicklung bis heute Konzepte Architektur User Interface Data and XML Base Class Library Visual Studio.NET Kapitel 1: C# Übersicht Common Language Runtime se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH se-rt C# 1.01 1 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Quelle: Microsoft Folie 4 2 .NET Framework Common Intermediate Language Das .NET Framework umfasst: Ö Laufzeitumgebung: Common Language Runtime (CLR) mit einer für alle .NET gemeinsamen Common Intermediate Language (CIL). Z.B. ist der Garbage Collector in der CLR implementiert Ö Typsystem: Common Language Specification (CLS)und Common Type System (CTS). Alle .NET-Sprachen basieren auf gemeinsamen Basis-Typen Ö .NET Bibliothek: Umfangreiche (Klassen-) Bibliothek z.B. für grafische Oberfläche, Web-Anwendungen, Datenbank, Sockets, XML, Multi-Threading, Kryptographie usw. se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Die CIL ist der „Befehlssatz“ der Virtual Machine von .NET Ö D.h. .NET-Anwendungen sind plattform-unabhängig in CIL geschrieben Ö Der CIL-Code sichert die kompatibilität zwischen den verschiedenen .NET Programmiersprachen Ö CIL ist eine „objektorientierte Assemblersprache“ se-rt Folie 5 .NET Framework: ein Sprachenmix www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 C# 1.01 Folie 7 Common Language Runtime Eine .NET-Anwendung kann in unterschiedlichen Sprachen geschrieben werden (z. B. C#, J#, C++/CLI, Visual Basic .NET) Eine Klasse, die in C# geschrieben ist, kann von einer Klasse in Visual Basic 2005 beerbt werden. Beide Klassen können Daten miteinander austauschen und Ausnahmen weiterreichen. Es gibt unter .NET keine „bevorzugte“ Programmiersprache. Vorteil: Jeder kann in der Sprache seiner Wahl programmieren. Die Klassenbibliothek, das Typsystem und die Laufzeitumgebung ist für alle .NET Sprachern gleich. se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C++/CLI nimmt Sonderstellung ein: wird (meistens) direkt in Maschinencode compiliert (d.h. CIL wird nicht verwendet) se-rt Folie 6 3 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 8 4 Common Language Runtime Thread Support COM Marshaler Type Checker Exception Manager Security Engine Debug Engine IL to Native Compilers Code Manager Garbage Collector Class Loader se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Quelle: Microsoft se-rt Folie 9 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Quelle: Microsoft Folie 11 Architektur des .NET Framework .NET Programmiersprachen Ein gemeinsames Typsystem für alle .NET Sprachen Kapitel 2: C# Grundlagen Umfangreiche Klassen-Bibliothek Laufzeitumgebung se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Quelle: Microsoft se-rt Folie 10 5 Kommentare, Bezeichner, reservierte Wörter Typenübersicht Operationen Arrays Kontrollstrukturen www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 6 Einfaches Beispiel UML-Darstellung Kommentare C#-Code Kommentierter Bereich Person.cs /* Dies ist ein Kommentar, der über mehrere Zeilen verläuft */ class Person { private double gehalt; Zeilenkommentar public double getGehalt() { return gehalt; } Person int x = 1; // Anfangswert // ab jetzt folgen Initialisierungen gehalt: double public void setGehalt(int g) { gehalt = g; } gehaltErhoehen() setGehalt getGehalt public void gehaltErhoehen() { gehalt = gehalt + 100; } } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH se-rt Folie 13 C# 1.01 Testrahmen für die Klasse Person PersonTest.cs donald.setGehalt(1000); Console.WriteLine("Donald verdient " + donald.getGehalt() + " EUR."); donald.gehaltErhoehen(); Console.WriteLine("Donald verdient " + donald.getGehalt() + " EUR."); } } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 15 C# 1.01 Reservierte Wörter Fest definierter Name der Startmethode class Program { static void Main(string[] args) { Person donald = new Person(); www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH abstract decimal float namespace return try as default for new sbyte typeof base delegate foreach null sealed uint bool do goto object short ulong break double if operator sizeof unchecked byte else implicit out stackalloc unsafe case enum in override static ushort catch event int params string using char explicit interface private struct virtual checked extern internal ref switch void class false is protected this volatile const finally lock public throw while continue fixed long readonly true yield se-rt Folie 14 7 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 16 8 Operationen Müssen mit einem Buchstaben beginnen _ zählt als Buchstabe Das Präfix @ ist zulässig und ermöglicht die Verwendung von Schlüsselwörtern als Bezeichner (aus stilistischen Gründen wird jedoch dringend davon abgeraten) Dann dürfen beliebige weitere Zeichen folgen Achtung: keine Schlüsselwörter verwenden Konventionen: Ö Klassennamen und Methodennamen werden groß geschrieben Ö Attribute werden klein geschrieben Ö Bei Wortzusammensetzungen wird der erste Buchstabe des Folgeworts groß geschrieben (z.B. CamelCase) Ö Lokale Variablen werden klein geschrieben se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Typenübersicht Belegung (Wertebereich) Abgebildet auf sbyte -27...27-1 (also: -128…127) System.SByte short -215...215-1 (also: -32768…32767) System.Int16 int -231...231-1 System.Int32 long -263...263-1 System.Int64 byte 0...28-1 (also: 0…255) System.Byte ushort 0...216-1 System.UInt16 uint 0...232-1 System.UInt32 ulong 0...264-1 System.UInt64 float +/-3.40282347 * 1038 (32 Bit IEEE 754) System.Single double +/-1.79769313486231570 * 10308 (64 Bit IEEE 754) System.Double decimal 128 Bit System.Decimal bool true, false System.Boolean char Unicode Zeichen System.Char www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH +, -, !, ~, ++, -- Unäre Operatoren: Vorzeichen, logisches Komplement, bitweises Komplement, Inkrement, Dekrement (typ) Typ-Konvertierung *, /, % Multiplikation, Division, Modulo +, - Addition, Subtraktion <<, >> Bitweise verschieben is as Typ-Prüfung, Typ-Wandlung <,>, >=, <=, ==, != Vergleiche & bitweise Und ^ bitweise Exklusives Oder | bitweise Oder && logisches Und || logisches Oder ?: Bedingungsoperator =, *=, /=, %=, +=, -=, <<=, >>=, >>>=, &=, ^=, |= Zuweisung www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 19 Spezielle Operatoren Typ se-rt Primäre Operatoren: Klammerung, Laufzeitinformation, Überlaufprüfung se-rt Folie 17 C# 1.01 (x) x.y f(x) a[x] x++ x–- new typeof sizeof checked unchecked Operator-Vorrang Bezeichner C# 1.01 Inkrement int a = 10, b; b = a++; // -> a = 11, b = 10 b = ++a; // -> a = 12, b = 12 Bedingungsoperator x = bedingung ? wertFallsBedErfuellt : wertFallsBedNichtErfuellt; Ist gleichbedeutend mit if(bedingung) { x = wertFallsBedErfuellt; } else { x = wertFallsBedNichtErfuellt; } se-rt Folie 18 9 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 20 10 Kontrollstrukturen: switch Aufzählungen Benannte Zahlen-Konstanten, standardmäßig 4 Byte Fallunterscheidung enum Farbe { rot, blau, gruen // die Werte sind 0, 1, 2 } switch (programmiersprache) { case "C": Console.WriteLine("Mühsam"); break; case "C++": Console.WriteLine("Besser"); break; case "C#": case "Java": Console.WriteLine("Noch besser"); break; case null: Console.WriteLine("?"); break; default: Console.WriteLine("Noch besser"); break; } // ... Farbe f = Farbe.blau; if(f == Farbe.rot) { ... } if(f == 1) { ... } // Achtung: Fehler! enum Jahreszeit { fruehling=1, sommer = 5, herbst = 12, winter = 20 } Die case-Marken müssen von einem break beendet werden Als Ausdruck im switch und den case-Marken können Integer, enum und string-Typen verwendet werden wird ein expliziter case nicht gefunden, wird der default-Block eingesprungen enum Status : byte { on, off } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 21 Kontrollstrukturen: if Folie 23 Schleifen: for, while, do-while for(int i = 0; i < 10; i++) { // ... } ... if(a > 20) { // ... } else { // ... } int j = 0; while(j < 10) { j++; // ... } Der if-Ausdruck muss vom Typ bool sein Der else-Teil kann entfallen www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Kontrollstrukturen: Schleifen if-Anweisung se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 break: Ablauf abbrechen und nach dem (innersten) Strukturende fortsetzen continue: Ablauf abbrechen und mit nächstem Schleifenwert fortsetzen int k = 0; do { k++; // ... } while(k < 10); se-rt Folie 22 11 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 24 12 Kontrollstrukturen: foreach int[] primzahlen = { 1, 3, 5, 7, 11 }; foreach (int x in primzahlen) { Console.WriteLine(x); } string abc = "abcdefghijklmnopqr"; foreach (char z in abc) { Console.WriteLine(z); } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Referenzparameter int x = 15; Console.WriteLine("x=" + x); test(ref x); Console.WriteLine("x=" + x); string text = "Hallo"; test(ref text); Console.WriteLine("text=" + text); Schleife für Kollektionen Arrays, Strings sowie alle Klassen, die das Interface IEnumerable implementieren "Bequeme" C# 1.01 x=15 i=15 i=99 x=99 text=Kaffee private static void test(ref int i) { Console.WriteLine("i=" + i); i = 99; Console.WriteLine("i=" + i); } private static void test(ref string s) { s = "Kaffee"; } se-rt Folie 25 Arrays www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 27 Out-Parameter out verhält sich wie ref als call by reference, es sind aber auch uninitialisierte Übergaben zulässig Ein- oder mehrdimensionale Felder Index beginnt bei 0 int[] a; int[] b = new int[5]; int[] c = new int[] { 7, 11, 99 }; int[] d = { 7, 11, 99 }; // Kurzform Person familieDuck[] = new Person[5]; // 5 Personenreferenzen string text1; string text2; test(out text1, out text2); Console.WriteLine("text1=" + text1); Console.WriteLine("text2=" + text2); // Hilfsfunktionen zur Arraybehandlung in der Klasse Array: Array.copy(d, a, 2); // kopiert d[0…1] nach a private static void test(out string s1, out string s2) { s1 = "Kaffee"; s2 = "Tasse"; text1=Kaffee } text2=Tasse int[][] e = new int[2][]; // 2 Zeilen, undef. Anzahl Spalten e[0] = { 1, 3, 5, 7 }; // Zeile 0 hat 4 Spalten e[0] = { 11, 13, 17, 19, 21 }; // Zeile 1 hat 5 Spalten int[,] f = new int[2, 3]; // "rechteckiges" Array int[,] g = { 1, 2, 3 }, { 4, 5, 6}}; se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 26 13 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 28 14 Variable Parameterliste partial class Der letzte Parameter einer Parameterliste kann als Array deklariert werden. Es kann dann eine beliebige Menge an Einzelwerten übergeben werden. Dieser Parameter muss mit dem Schlüsselwort params gekennzeichnet werden Eine Klasse kann auf mehrere Dateien aufgesplittet werden. Datei1.cs namespace BusinessObject { partial class Person { // ... erster Teil ... } } int ergebnis; summe(ergebnis, 1, 3, 6, 8, 9, 12, 8); Console.WriteLine("ergebnis=" + ergebnis); Datei2.cs namespace BusinessObject { partial class Person { // ... zweiter Teil ... } } private static void summe(out int ergebnis, params int[] werte) { ergebnis = 0; foreach (int i in werte) ergebnis += i; } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 29 Namensräume Folie 31 Wenn bei arithmetischen Operationen der Wertebereich überschritten wird, tritt kein Fehler auf. int x = 1000000; // 10 hoch 7 Alternativ zu „using“ kann der vollqualifizierte Name verwendet werden: y=-727379968 int y = x * x; Console.WriteLine("y=" + y); Abhilfe: der Operator checked Namensbereich1.B b = ... int x = 1000000; // 10 hoch 7 namespace MeinProjekt { using Namensbereich1; class Program { A a; // ... } } se-rt C# 1.01 Zahlenüberlauf Namensräume fassen mehrere Klassen, Structs, Interfaces, Enumerationen und Delegates zu einer logischen Einheit zusammen namespace Namensbereich1 { class A { … } class B { … } } www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH checked { int y = x * x; Console.WriteLine("y=" + x); } Unbehandelte Ausnahme: System.OverflowException: Die arithmetische Operation hat einen Überlauf verursacht. Die Überlaufprüfung kann auch über Compiler-Einstellungen ein/ausgeschaltet werden C# 1.01 se-rt Folie 30 15 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 32 16 Zeiger – unsafe und fixed String Innerhalb von unsafe-Methoden oder Code-Bereichen können Zeigeroperationen ausgeführt werden class UnsafeTest { unsafe static void quadrat(int* p) { *p *= *p; } unsafe static void Main() { int i = 5; quadrat(&i); Console.WriteLine(i); } } www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH // angenommen, x ist // ein Attribut von p unsafe { fixed (int* b = &p.x) { *b = 99; // ... } } string s1 = "Kaffee"; string s2 = "tasse"; string s3 = s1 + s2; Console.WriteLine(s3); Console.WriteLine(s3.ToUpper()); Console.WriteLine(s3.IndexOf(s2)); Console.WriteLine(s3[7]); Über das Schlüsselwort fixed wird der Garbage Collector angewiesen, referenzierten Speicher (z.B. von Arrays oder Objekt-Attributen) nicht freizugeben. Der Gültigkeitsbereich des nicht sicheren Kontexts reicht von der Parameterliste bis zum Methodenende, sodass auch in der Parameterliste Zeiger verwendet werden können se-rt Der Datentyp zur Zeichenkettenbehandlung ist string Die string-Methoden (z.B. Insert, Remove, usw.) sind unverändernd, d.h. der Empfängerstring ändert sich nicht. Veränderbare Strings ÆStringBuilder C# 1.01 Ausgabe: Kaffeetasse KAFFEETASSE 6 A string s4 = s3.Insert(6, "unter"); Kaffeetasse Kaffeeuntertasse Console.WriteLine(s3); Console.WriteLine(s4); se-rt Folie 33 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 35 Datum Datum wird durch die Klasse DateTime behandelt Der Abstand zwischen zwei DateTime-Objekten ist ein Objekt der Klasse TimeSpan Kapitel 3: C# Basisklassen se-rt DateTime heute = DateTime.Now; DateTime weihnachten2009 = new DateTime(2009, 12, 24, 12, 0, 0); Console.WriteLine(heute.ToString("dd.MM.yyyy HH:mm")); Console.WriteLine(weihnachten2009.ToString("d")); Console.WriteLine(weihnachten2009.ToString("D")); String Datum Arrays Einfache Datei Ein-/Ausgabe www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH TimeSpan ts = weihnachten2009 - heute; Console.WriteLine("Tage bis Weihnachten:" + ts.Days); Ausgabe: se-rt C# 1.01 17 30.09.2009 16:08 24.12.2009 Donnerstag, 24. Dezember 2009 Tage bis Weihnachten:84 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 36 18 Konsolen-Ausgabe Textdatei schreiben Console.Write(x) Console.WriteLine(x) FileStream fs = new FileStream( "C:\\Daten\\Quadrate.txt", FileMode.Create); StreamWriter writer = new StreamWriter(fs); Console.WriteLine("{0}, {1}", a, b) Platzhalter-Syntax "{" writer.WriteLine("Quadratzahlen"); for (int i = 0; i < 20; i++) { writer.WriteLine("i={0} i*i={1}", i, i * i); } writer.Close(); fs.Close(); n ["," width] [":" format [precision] "}" Ö n: Argumentnummer Ö width: Feldbreite (positiv: rechtsbündig, negativ: linksbündig) Ö format (d: Dezimalformat, f: Fixpunktformat, c: Währungsformat, …) Ö precision: Anzahl Nachkommastellen double d1 = 3.149; Console.WriteLine("{0,2:f2}", d1); se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH 3,15 se-rt Folie 37 C# 1.01 Tastatur-Eingabe www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Folie 39 C# 1.01 Textdatei lesen Console.Read() Æ liefert als int die Zeichen Console.ReadLine() Æliefert die Eingabe als string string eingabe; do { eingabe = Console.ReadLine(); Console.WriteLine("Ihre Eingabe:" + eingabe); } while (eingabe != "Ende"); se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH FileStream fr = new FileStream( "C:\\Daten\\Quadrate.txt", FileMode.Open); StreamReader reader = new StreamReader(fr); string zeile; while((zeile = reader.ReadLine()) != null) { Console.WriteLine(zeile); } reader.Close(); fr.Close(); Hallo Ihre Eingabe:Hallo Test Ihre Eingabe:Test Ende Ihre Eingabe:Ende C# 1.01 se-rt Folie 38 19 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Quadratzahlen i=0 i*i=0 i=1 i*i=1 i=2 i*i=4 i=3 i*i=9 i=4 i*i=16 i=5 i*i=25 i=6 i*i=36 i=7 i*i=49 i=8 i*i=64 i=9 i*i=81 ... Folie 40 20 Sichtbarkeiten public Öffentlich – Zugriff generell möglich private Privat – Zugriff nur von Objekten der selben Klasse Kapitel 4: C# Klassen se-rt Attribute ohne Sichtbarkeitsangabe sind private Sichtbarkeiten Attribute, Methoden Properties Konstruktor, Destruktor Klassenmethoden und –attribute Operatorenüberladung structs www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Beispiel: Klasse „Person“ in C# internal Wie public, aber auf das „Assembly“ beschränkt class Person { protected double gehalt; Attribute Methoden public void gehaltErhoehen() { // es gibt für alle 100 EUR mehr gehalt = gehalt + 100; } // ... se-rt Folie 43 donald.Gehalt = 1000; double wert = donald.Gehalt; // ... } } www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 public double Gehalt { // ein "Property" set { Console.WriteLine("Set"); gehalt = value; } get { Console.WriteLine("Get"); return gehalt; } } public double getGehalt() { return gehalt; } public void setGehalt(double g) { gehalt = g; } www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Properties Klassendefinition protected string name; protected double gehalt; protected int alter; Wie private, aber zusätzlich ist der Zugriff von Kindklassen möglich se-rt C# 1.01 class Person { protected C# 1.01 se-rt Folie 42 21 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 44 22 Destruktor Methodenüberladung Methoden mit gleichem Bezeichner können mit unterschiedlicher Signatur „überladen“ werden (overloading) Beispiel: public void { // ... } public void { // ... } public void { // ... } public void { // ... } se-rt Der Destruktor bildet das Gegenstück zum Konstruktor, der Aufrufzeitpunkt ist aber nicht vorhersehbar Der Destruktor hat den Namen wie die Klasse mit ~ (genau wie in C++) Destruktoren sind parameterlos und ohne spezifizierte Sichtbarkeit Aber Achtung: der Aufrufzeitpunkt in unspezifiziert! Im Gegensatz zu C++ sind bei C# Destruktoren meist unnötig print() print(int anzahl) print(string infoText) Eine Ergänzung zum Destruktor bildet das Interface IDisposable Ö Es muss in der Implementierung die Methode Dispose implementiert werden Ö Üblicherweise erfolgt der Aufruf vom Destruktor aus print(int anzahl, string infoText) www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 45 Konstruktor Klassenvariablen werden je Klasse einmal angelegt Klassenmethoden werden über den Klassenbezeichner aufgerufen: Person.getAnzahlPersonen() Person donald = new Person("Donald", 45, 400); Person daisy = new Person(); // ... class Person { private static int anzahlPersonen; class Person { // ... public Person() : this("nobody", 0, 0) { // ... } public Person(string n, int a, double g) { name = n; alter = a; gehalt = g; } } www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Folie 47 C# 1.01 Klassenmethoden und -variablen Der Konstruktor wird beim Erzeugen eines Objekts aufgerufen Kontruktoren können überladen werden se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 public static int getAnzahlPersonen() { return anzahlPersonen; } Attribut anzahlPersonen wird von allen Objekten der Klasse Person geteilt. public Person() { anzahlPersonen ++; // ... } } se-rt Folie 46 23 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 48 24 Klassen und Instanzen Klassenattribut: Alle Objekte einer Klasse teilen sich das eine Attribut Überladene Operatoren Die arithmetischen Operatoren (+, -, *, /, …) sowie die Vergleichsoperatoren (==, !=, >, …) können für eine Klasse überladen werden Der Methodenname ergibt sich aus „operator“ und dem Operatorzeichen (z. B. „operator+“) Die Methode muss public static definiert werden Instanzattribut: Jedes Objekt besitzt physisch ein eigenes Attribut class Person { // ... private static int anzahlPersonen; // ... }; class Person { // ... private int alter; // ... } Klassenmethode: Aufruf erfolgt über den Klassennamen: Person.getAnzahlPersonen() Instanzmethode: Aufruf erfolgt über den Objektbezeicher: wert = donald.getAlter(); class Person { // ... public static int getAnzahlPers(); // ... } class Person { // ... public int getAlter(); // ... } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Ö Unäre Operatoren haben einen Übergabeparameter Ö Binäre Operatoren haben zwei Übergabeparameter se-rt Folie 49 Statischer Konstruktor www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 51 Beispiel: Klasse „Bruch“ Dient der Initialisierung von Klassenattributen Hat keine Parameter class Bruch { private int zaehler; private int nenner; Achtung: es wird keine Reihenfolge beim Aufruf der statischen Konstruktoren garantiert public Bruch() : this (0, 1) { } public Bruch(int z, int n) { zaehler = z; nenner = n; } class Person { // ... static Person() { anzahlPersonen = 0; } // ... }; public static Bruch operator+(Bruch a, Bruch b) { return new Bruch(a.zaehler * b.nenner + b.zaehler * a.nenner, a.nenner * b.nenner); } public void print() { Console.WriteLine(zaehler+"/"+nenner); } } Hinweis: Klassenattribute – wie alle Attribute - werden standardmäßig mit 0 initialisiert se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 50 25 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 52 26 Typwandlung Eingebettete Klassen Eine Typwandlung eines Referenztyps nach int, double oder in einen anderen Referenztyp kann über einen überladenen castOperator erfolgen Dieser cast kann „explizit“ oder „implizit“ erfolgen: class A { public void a() { Console.WriteLine("a"); B b = new B(); b.b(); } Bruch a = ... Bruch b = a + 2; // impliziter cast der "2" (ein int) in Bruch A a1 = new A(); a.a(); A.B b = new B.C(); // Fehler! A.C c = new A.C(); // OK c.c(); class B // nicht öffentlich: nur innerhalb A sichtbar { public void b() { Console.WriteLine("b"); } } double c = (double)b; // expliziter cast des Bruch b in double String d = (string)b; // expliziter cast des Bruch b in string public class C // öffentlich: als A.C auch außerhalb von A sichtbar { public void c() { Console.WriteLine("c"); } } } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 53 Typwandlung Folie 55 Statische Klassen können nur statische Attribute oder Methoden haben class Bruch { // ... public static implicit operator Bruch(int x) // int Æ Bruch { return new Bruch(x, 1); } public static explicit operator double(Bruch b) // Bruch Æ double { return ((double)b.zaehler) / b.nenner; } public static explicit operator string(Bruch b) // Bruch Æ string { return b.zaehler + "/" + b.nenner; } } www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Statische Klassen Eine Typwandlung erfolgt durch überladene cast-Operatoren se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 static class Konstanten { public static const double dmInEuro = 1.95583; public static const double mwstSatz = 0.19; static double nachEuro(double dm) { return dmInEuro * dm; } } se-rt Folie 54 27 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 56 28 structs Vererbung structs sind Werttypen Zuweisungen zwischen structs kopieren die Attribute (und nicht die Objektreferenz!) struct Punkt { public int m_x; public int m_y; Person name alter gehalt Punkt p1 = new Punkt(1, 1); Punkt p2; p2 = p1; p2.print(); p1.m_x = 99; P1.print(); p2.print(); public Punkt(int x, int y) { m_x = x; Ein m_y = y; Ein } Ein public void print() { Console.WriteLine("Ein Punkt x={0} } gehaltErhoehen Punkt x=1 y=1 Punkt x=99 y=1 Punkt x=1 y=1 Programmierer firmenWagen progSprache y={1}", m_x, m_y); Manager } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 57 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Spezialisierung Ö Die Kindklassen „Programmierer“ und „Manager“ werden von der Klasse „Person“ abgeleitet - sind Spezialisierungen der Klasse „Person“ Generalsierung Ö Die Gemeinsamkeiten von „Programmierer“ und „Manager“ werden in der Vaterklasse „Person“ vereinigt – „Person“ ist Generalisierung von „Programmierer“ und „Manager“ C# 1.01 Folie 59 Vererbung A subclass may inherit the structure and behavior of its superclass. Kapitel 4: Vererbung se-rt Prinzip Laufzeitbindung Überschreiben und verdecken Abstrakte Klassen Interface Die Klasse Object www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH se-rt C# 1.01 29 Quelle: Booch, Grady, Object-Oriented Analysis and Design with Applications, 1991 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 60 30 Polymorphismus UML-Darstellung Person gehaltErhoehen() Überschreiben und Verdecken Laufzeitbindung einer Methode muss ausdrücklich über virtual festgelegt werden. Methoden können in Kindklassen mit selbem Namen erneut implementiert Damit entsteht unterschiedliches Verhalten, die öffentliche Struktur bleibt gleich Die Objekte können sich autonom verhalten class Person { public virtual void gehaltErhoehen() { gehalt = gehalt + 100; } } Programmierer Person p = ... p.gehaltErhoehen(); Bindung erfolgt dynamisch gehaltErhoehen() In einer Kindklasse kann eine Methode definiert werden als Ö new: Vaterklassenimplementierung wird „verdeckt“; keine Laufzeitbindung Ö override: Vaterklassenimplementierung wird überschrieben, Laufzeitbindung (virtual) erforderlich C#-Code class Person { public void gehaltErhoehen() { gehalt = gehalt + 100; } } se-rt class Programmierer : Person { public new void gehaltErhoehen() { gehalt = gehalt * 2; } } www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 61 Folie 63 Überschreibende (override) oder verdeckende (new) Methoden müssen dieselbe Signatur haben wie die entsprechende Methode der Vaterklasse Ö Gleiche Typen Ö Gleiche Parameterzahl Ö Gleiche Parameterart (ref, out) Ö Gleiche Sichtbarkeit In einer override/new-Methode kann die Implementierung der Vaterklasse aufgerufen werden: C#-Code Person donald = new Person(); Programmierer trick = new Programmierer(); donald.setGehalt(1000); trick.setGehalt(1000); Console.WriteLine("Donald verdient " + donald.getGehalt() + " EUR."); Console.WriteLine("Trick verdient " + trick.getGehalt() + " EUR."); donald.gehaltErhoehen(); trick.gehaltErhoehen(); Console.WriteLine("Donald verdient " + donald.getGehalt() + " EUR."); Console.WriteLine("Trick verdient " + trick.getGehalt() + " EUR."); class Programmierer { public override void gehaltErhoehen() { base.gehaltErhoehen(); // ... } } Ausgabe: Donald verdient 1000 EUR. Trick verdient 1000 EUR. Donald verdient 1100 EUR. Trick verdient 2000 EUR. www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 override/new/base Beispiel: Polymorphie se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 62 31 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 64 32 Verdecken bei statischen Methoden Bildung von Vererbung Statische Methoden - diese kennen ja keine dynamische Bindung – können nicht überschrieben (override) werden. Verdecken (new) ist aber möglich. 1 SachVersicherungsVertrag SachVersicherungsVertrag www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 65 Statische vs. dynamische Bindung VersicherungsVertrag se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Eine weitere Klasse nutzt die zuvor stattgefundene Generalisierung Dieser Vorgang wird nun als Spezialisierung bezeichnet SachVersicherungsVertrag LebenVersicherungsVertrag JahresBeitrag VersicherterGegenstand RisikoLVAnteil BegünstigtePerson Laufzeit www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Folie 67 C# 1.01 Realisierung einer "ist-ein" Beziehung im Gegensatz zu einer "hat-ein" Beziehung der Assoziation Ö Ein LV-Vertrag ist ein Versicherungsvertrag Ö Ein Auto hat Räder Vererbung im fachlichen Kontext ist selten sinnvoll Alternative zur Vererbung ist eine Aggregation Person p = new Programmierer() p.m(); Bindung erfolgt statisch, es wird die Implementierung des Typs von p aufgerufen. D.h. es wird m von Person aufgerufen! Dynamische Bindung class Person { public virtual void m() { ... } } class Programmierer { public override void m() { ... } } Es wird eine mögliche Wiederverwendbarkeit erkennbar Allgemeingültige Merkmale werden generalisiert Vererbung vs. Aggregation Statische Bindung class Person { public void m() { ... } } class Programmierer { public new void m() { ... } } VersicherungsNehmer AbschlussDatum JahresBeitrag VersicherterGegenstand VersicherungsNehmer AbschlußDatum se-rt VersicherungsNehmer AbschlussDatum Zunächst entsteht aus den bekannten Anforderungen eine konkrete Klasse. Motivation zur Vererbung besteht nicht 3 VersicherungsVertrag 2 VersicherungsNehmer AbschlussDatum JahresBeitrag VersicherterGegenstand A Person B Person p = new Programmierer() Person p.m(); Student Bindung erfolgt dynamisch. Es wird m von Programmierer aufgerufen! C# 1.01 se-rt Folie 66 33 0..1 Student Ein Student ist eine Person (?) Wie wird mit dem Studenten in (A) verfahren, wenn das Studium beendet wurde? www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 68 34 Vererbung abstrakter Methoden „Versiegelte“ Klassen und Methoden Von versiegelten (sealed) Klassen können keine Kindklassen abgeleitet werden Versiegelte Methoden können nicht überschrieben oder verdeckt werden Wird eine abstrakte Methode vererbt, wird deren Implementierung in den Kindklassen erzwungen Vorteil: lässt sich auch keine generische Implementierung festlegen, so ist doch ein gemeinsames Interface erzwingbar PersistentesObjekt Die Klasse Person implementiert die abstrakte Methode Store() getStoreSQL() : String Person getStoreSQL() : String se-rt VersicherungsVertrag class Konto { public double getSaldo() { ... } public sealed Person getInhaber(); // kann nicht über// schrieben werden Eine abstrakte Methode erzwingt die Implementierung in den Kindklassen Klassen mit abstrakten Methoden können selbst keine Objekte instanzieren } sealed class GiroKonto : Konto // kann nicht abgeleitet { // werden // … } getStoreSQL() : String www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 69 Abstrakte Methoden definieren eine Schnittstelle, die Implementierung bleibt den Kindklassen überlassen Eine abstrakte Klasse besteht aus mind. einer abstrakten Methode sowie weiteren (konkreten) Methoden und Attributen Abstrakte Methoden werden dynamisch gebunden C# 1.01 Folie 71 System.Object oder object ist die implizite Vaterklasse aller Klassen class Object { public Type GetType { ... } public virtual bool Equals(object o) { ... } public virtual string ToString() { ... } public virtual int GetHashCode() { ... } protected object MemberwiseClone() { ... } ... } abstract class PersistentObject { public int createUniqueID() { ... } public abstract Result store(); public virtual bool beginTransaction() { ... }; abstract void commit(); abstract void rollback(); } www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Die Klasse Object Abstrakte Klassen und Methoden se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Object o = new Person(); Person p = o; // nicht OK! Person p = (Person)o; // OK se-rt Folie 70 35 // OK www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 72 36 Interface Typwandlungen - casts Die Typwandlung über den cast-Operator wirft eine InvalidCastException falls die Typwandlung nicht möglich ist Methoden oder Properties in Interfaces sind „automatisch“ public, abstract und virtual Der Interface-Name steht als „normaler“ Datentyp zur Verfügung 1 Programmierer p = (Programmierer)donald; interface IPerson { double Gehalt { set; get; } void gehaltErhoehen(); void print(); } class Person : IPerson { ... } Person donald = ... if(donald is Programmierer) { } Programmierer p = donald as Programmierer; IPerson donald = new Person(); IPerson trick = new Programmierer(); ... se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH 2 if (p == null) { Console.WriteLine("Donald ist kein Programmierer"); } se-rt Folie 73 C# 1.01 Interface Label-Darstellung: hatPlaetzeFrei() einbuchen() Store() Delete() Load() se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 75 Die Klasse Object Alle Klassen (alle selbstgeschriebenen und alle Klassen der .NET Bibliothek) sind Kindklassen der Klasse object (bzw. System.Object) Ein Interface ist einer Klasse mit ausschließlich abstrakten Methoden gleichzusetzen Interfaces werden „implementiert" Eine Klasse kann viele Interfaces implementieren Interfaces definieren Methoden, die von den Implementierungen implementiert werden müssen Veranstaltung datumVon : Date datumBis : Date bezeichnung : String preis : Waehrungsbetrag Person donald = ... class Object { public Type GetType() { ... } public virtual bool Equals(object o) { ... } public virtual string ToString() { ... } public virtual int GetHashCode() { ... } protected object MemberwiseClone() { ... } ... } Icon-Darstellung: <<Interface>> PersistentesObjekt Store() Delete() Load() www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Veranstaltung datumVon : Date datumBis : Date bezeichnung : String preis : Waehrungsbetrag hatPlaetzeFrei() einbuchen() Store() Delete() Load() C# 1.01 PersistentesObjek t Store() Delete() Load() se-rt Folie 74 37 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 76 38 Objektkopie Exceptions Die protected-Methode MemberWiseClone() von object dient dem Erstellen von (flachen) Kopien eines Objekts Alle Attribute werden dabei umkopiert Dienen zur Fehlerbehandlung In C# (und den meisten anderen OO-Sprachen) werden Fehler, die innerhalb einer Methode auftreten, durch eine Exception dem Aufrufer mitgeteilt Tritt in einer Methode ein Fehler auf, wird dieser „geworfen“ (throw). Der Aufrufer der Methode „fängt“ (catch) den Fehler public class Person { public Person Clone() { return ((Person)MemberwiseClone()); } // ... } Fehler werden schließlich in einem separaten „catch“-Block behandelt. Hierdurch entsteht eine Trennung von „produktivem“ Programmcode und der Fehlerbehandlung Person p1 = ... Person p2 = p1.Clone(); Falls Beziehungen mit kopiert werden aollen, kann alternativ auch das Interface ICloneable implementiert werden; in der Methode public object Clone() muss dann das neue Objekt selbst generiert und zurückgeliefert werden se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 77 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 79 Exceptions - throw Beispiel: Das Werfen der Exception Kapitel 5 Ausnahmen und Schablonen void setGehalt(double g) { if(g > 1000) { throw new VerdientZuVielException(g); } Standardmäßig erfolgt der „Stack-Trace“, wenn eine Exception nicht gefangen wird // hier geht’s "Normal" weiter gehalt = g; Ausnahmen - Exceptions Generische Klassen - template } Unbehandelte Ausnahme: Person1.Program+VerdientZuVielException: Die Person verdient zu viel: 1200 bei Program.Person.setGehalt(Double g) in Program.cs:Zeile 71. bei Program.Main(String[] args) in Program.cs:Zeile 27. se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH se-rt C# 1.01 39 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 80 40 „Eigene“ Exception-Klassen Beispiel: Exception in .NET Framework Exception-Klassen müssen von der Klasse Exception oder ApplicationException ableiten class VerdientZuVielException : Exception { private double betrag; try { FileStream s = new FileStream("personen.dat", FileMode.Open); IFormatter f = new BinaryFormatter(); personen = f.Deserialize(s) as List<Person>; s.Close(); // ... } catch (IOException ex) { MessageBox.Show(ex.Message, "Fehler beim Datenzugriff", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } public VerdientZuVielException() {} public VerdientZuVielException(double b) { betrag = b; } public double getBetrag() { return betrag; } public override string Message { get { return "Die Person verdient zu viel: " + getBetrag(); } } } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 81 Exceptions fangen Folie 83 Das „potentielle“ Werfen einer Exception muss in C# nicht in der Methodensignatur angekündigt werden Der Compiler fordert auch keinen try-catch um einen Codebereich, der potentiell Exceptions werfen kann try { trick.setGehalt(1200); // ... } catch(VerdientZuVielException vzve) { Console.WriteLine("So viel darf er nicht verdienen: " + vzve.getBetrag()); // oder: Console.WriteLine(vzve.Message); } catch(Exception e) { Console.WriteLine("Hier ist was Schlimmes passiert: " + e.Message); } www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Bemerkungen zu Exceptions Person trick; // ... se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 82 41 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 84 42 template template Beispiel „Stack“ (2) Template-Klassen (Schablonenklassen, Generische Klassen, Generics) sind Klassen, die zur Compilezeit in Teilen parametrisiert werden können Templates werden besonders häufig bei Kollektionen verwendet Beispiel: Ö Liste<Person> personenListe; Ö Liste<int> intListe Ö Stack<String> einStringStack; Klassen werden zur Kompilezeit „instanziert“; Liste<Person> ist eine andere Klasse als Liste<int> Stack<Person> leute = new Stack<Person>(); leute.push(donald); leute.push(trick); leute.push(track); leute.push(tick); leute.push(daisy); Console.WriteLine(leute.pop().ToString()); Console.WriteLine(leute.pop().ToString()); Console.WriteLine(leute.pop().ToString()); Console.WriteLine(leute.pop().ToString()); Console.WriteLine(leute.pop().ToString()); Daisy Tick Track Trick Donald se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH se-rt Folie 85 C# 1.01 template Beispiel „Stack“ (1) 7 7 7 7 45 Jahre Jahre Jahre Jahre Jahre www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH alt, alt, alt, alt, alt, 300,00 200,00 400,00 1100,00 1100,00 EUR EUR EUR EUR EUR C# 1.01 Gehalt Gehalt Gehalt Gehalt Gehalt Folie 87 Vererbung bei templates (1) Template-Klasse wird Kindklasse einer „normalen“ Klasse class Stack<Element> { private Element[] speicherbereich; private int stackEnde = 0; public Stack() { speicherbereich = new Element[10]; } public void push(Element e) { speicherbereich[stackEnde] = e; stackEnde++; } public Element pop() { Element e = speicherbereich[stackEnde - 1]; stackEnde--; return e; } public int size() { return stackEnde; } } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Stack < Person > leute; class List { public int size() { ... } }; class Stack<Element> : List { // ... } se-rt Folie 86 43 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 88 44 Vererbung bei templates (2) Delegates Template-Klasse wird Kindklasse einer Template-Klasse Ein „delegate“ (Æ Delegierter, Vertreter) „vertritt“ einen Methodenaufruf Über das Schlüsselwort delegate wird ein Delegate-Datentyp definiert – zu beachten ist die Signatrur! Von diesem Datentyp werden Objekte erzeugt, die im Konstruktor den Methodenaufruf erhalten class List<Element> { protected Element[] speicherbereich; }; class Stack<Element> : List<Element> { // ... delegate void IchVertrete(); // der Datentyp der Vertreters } IchVertrete donaldDrucktSich = new IchVertrete(donald.print); IchVertrete daisyDrucktSich = new IchVertrete(daisy.print); // … donaldDrucktSich(); daisyDrucktSich(); Dieser Typ kann auch konkret festgelegt werden (z.B. Object) se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 89 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 91 Multicast-Delegates Ein einziger Delegate kann gleich mehrere Methodenaufrufe zugewiesen bekommen Kapitel 6 Delegates und Attribute se-rt IchVertreteWas druckAktion = new IchVertreteWas(donald.print); druckAktion += new IchVertreteWas(daisy.print); // druckAktion(); Vertreter - delegate Events Threads Attribute Reflektion www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH // führt beide print-Methoden aus Kurzschriebweise IchVertreteWas druckAktion = donald.print; // druckAktion(); se-rt C# 1.01 45 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 92 46 Events Anonyme Methoden Events sind lokal in einer Klasse gekapselte Vertreter Übung: ein „flexibler“ Rechner delegate void AenderungsInfo(string senderInfo); class PersonenView1 { public PersonenView1(Person p) { p.aenderungsInfo += Anzeige; } public void Anzeige(string text) { Console.WriteLine("View1: " + text); } } Rechner r = new Rechner(); int[] zahlen = { 1, 2, 3, 4, 5}; int a = r.rechne(r.bildeSumme, zahlen); int b = r.rechne(r.bildeMax, zahlen); int resultat = 1; r.rechne(delegate(int x) { resultat *= x; }, zahlen); PersonenView1 view1 = new PersonenView1(donald); donald.gehaltErhoehen(); class Person { public event AenderungsInfo aenderungsInfo; // ... public void gehaltErhoehen() { // ... aenderungsInfo(this.ToString()); } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 93 Beispiel delegate (1) www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Folie 95 C# 1.01 Threads Übung: ein „flexibler“ Rechner using System.Threading Person donald = new Person("Donald", 45, 1000); delegate void Rechnen(int i); class Rechner { public int erg = 0; public void bildeSumme(int i) { erg += i; } public void bildeMax(int i) { erg = i > erg ? i : erg; } Thread t = new Thread(new ThreadStart(donald.print)); t.Start(); // Æ ruft donald.print auf Thread.Sleep(100); // 100ms den aktuellen Thread anhalten public int rechne(Rechnen rechnen, int[] zahlen) { erg = 0; foreach(int i in zahlen) { rechnen(i); } return erg; } Delegate Synchronisation } lock(object) { // ... } Rechner r = new Rechner(); int[] zahlen = { 1, 2, 3, 4, 5}; int a = r.rechne(r.bildeSumme, zahlen); int b = r.rechne(r.bildeMax, zahlen); se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 94 47 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 96 48 Synchronisation Attribute auswerten Attribute können auch zur Laufzeit ausgewertet werden Person donald = new Person("Donald", 45, 1000); Thread t1 = new Thread(new ThreadStart(donald.zaehleLangsam)); Thread t2 = new Thread(new ThreadStart(donald.zaehleLangsam)); t1.Start(); t2.Start(); // ... Type t = typeof(AltesDing); object[] attributes = t.GetCustomAttributes(typeof(VeraltetAttribute), true); class Person { // ... private int counter = 0; public void zaehleLangsam() { for (int i = 0; i < 100; i++) { lock (this) { int tmp = counter; Thread.Sleep(100); counter = tmp + 1; Console.WriteLine("counter=" + counter); } } } } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 foreach (object o in attributes) { if (o is VeraltetAttribute) { Console.WriteLine(((VeraltetAttribute)attributes[0]).Message); } } // ... se-rt Folie 97 Attribute www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 99 Attribut DllImport Der extern-Modifizierer wird verwendet, um eine extern implementierte Methode zu deklarieren. Methoden mit dem Attribut „DllImport“ werden über die InteropServices behandelt C#-Sprachelemente, wie z.B. Klassen, Methoden oder Attribute können attributiert werden (Java-Bezeichnung: Annotation) Attribute werden in [..] vor das betreffende Sprachelement geschrieben [Veraltet("Bitte nicht mehr verwenden")] class AltesDing { // ... } using System.Runtime.InteropServices class Test { [DllImport("user32.dll")] public static extern int MessageBox(int hParent, string text, string caption, int type); public sealed class VeraltetAttribute : Attribute { string message; public string Message { get { return message; } } public VeraltetAttribute(string m) { message = m; } } public static void Anzeige() { MessageBox(0, "Hallo von C#", "Eine Messagebox", 1); } } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 98 49 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 100 50 Attribut: Serializable Kommentare zur Dokumentation Objekte von Klassen mit dem Attribut [Serializable] können in einen Datenstrom z.B. in eine Datei serialisiert werden Attribute, die nicht gespeichert werden sollen, werden als [NonSerialized] attributiert /// <summary> /// natürliche Personen gem. Spezifikation Kapitel 4 /// </summary> class Person : IPerson { [Serializable] class Person { [NonSerialized] private static int anzahlPersonen = 0; protected string name; protected int alter; protected double gehalt; // ... } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 101 Attribut: Serializable www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 103 Reflektion Unter Reflektion wird der Zugriff auf Klasseneigenschaften, Methoden und Attribute verstanden System.Reflection Beispiel: der Aufruf einer Methode using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; Person donald = … Object o = donald; Type type = o.GetType(); MethodInfo diePrintMethode = type.GetMethod("gehaltErhoehen"); // Objekt in Datei schreiben FileStream s = new FileStream("duck.dat", FileMode.Create); IFormatter f = new BinaryFormatter(); f.Serialize(s, donald); s.Close(); diePrintMethode.Invoke(o, new object[0]); // Methodenaufruf // Objekt aus Datei lesen FileStream s = new FileStream("duck.dat", FileMode.Open); IFormatter f = new BinaryFormatter(); Person ps = f.Deserialize(s) as Person; s.Close(); Bei überladenen Methoden (Methoden mit dem gleichen Namen und unterschiedlicher Parameterliste) wird die GetMethods()-Methode von Type verwendet und über die MethodInfo-Objekte wird die gesuchte Methode ausgewählt. Praktischer sind Collection-Klassen, die sich selbst und ihre enthaltenen Elemente serialisieren (z.B. List<T>) se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 102 51 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 104 52 Kapitel 6 .NET Klassenbibliothek Kapitel 7 Kollektionen Übersicht se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH se-rt C# 1.01 Klassenbibliothek UI HtmlControls Discovery WebControls System.Windows.Forms Design Protocols C# 1.01 Klassen, die das Interface IEnumerable implementieren, können wie eine Kollektion behandelt werden. yield Æeinbringen trägt zu einer Kollektion bei ComponentModel System.Drawing Caching Security Drawing2D Printing Configuration SessionState Imaging Text System.Data public class Wochentage : System.Collections.IEnumerable { public System.Collections.IEnumerator GetEnumerator() { yield return "Sonntag"; yield return "Montag"; yield return "Dienstag"; yield return "Mittwoch"; yield return "Donnerstag"; yield return "Freitag"; yield return "Samstag"; } } System.Xml ADO SQL XSLT Design SQLTypes XPath Serialization System Collections IO Security Configuration Net ServiceProcess Diagnostics Reflection Text Remoting Globalization Resources Threading Serialization se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Das Interface IEnumerable System.Web Services Description Iteratoren - IEnumerable Indexer ICollection ICollection<T> www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Runtime InteropServices se-rt Folie 106 53 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 108 54 Das Interface IEnumerable Collection-Typen Beispiel: Verwendung in einer foreach-Schleife ICollection int Count void CopyTo(Array a, int pos) IEnumerator GetEnumerator() … Wochentage wochentage = new Wochentage(); foreach (string wochentag in wochentage) { Console.WriteLine(wochentag); } IList object this[int index] void Clear() int Add(obejct o) … IDictionary ICollection Keys ICollection Values void Add(object key, object value) … ArrayList se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 109 Der Indexer www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Hashtable C# 1.01 Folie 111 Klasse ArrayList Zugriffsmöglichkeit über den Index-Operator Es können get und set implementiert werden Standard-Klasse für Array-Funktionen Wochentage wochentage = new Wochentage(); Console.WriteLine(wochentage[3]); ArrayList familieDuck = new ArrayList(); familieDuck.Add(donald); familieDuck.Insert(0, daisy); familieDuck.Add(trick); familieDuck.Add(track); familieDuck.Insert(1, tick); public class Wochentage : ... { string[] wochentage = { "Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag" }; foreach (object o in familieDuck) { Console.WriteLine(o.ToString()); } public string this[int index] { get { return wochentage[index]; } } } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 110 55 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 112 56 Klasse Hashtable Klasse List<T> Implementiert eine Schlüssel-Wert-Beziehung Standard-Klasse für Array-Funktionen Hashtable woerterbuch = new Hashtable(); woerterbuch.Add("rot", "red"); woerterbuch.Add("blau", "blue"); woerterbuch.Add("schwarz", "black"); woerterbuch.Add("gelb", "yellow"); List<Person> familieDuck = new List<Person>(); familieDuck.Add(donald); familieDuck.Insert(0, daisy); familieDuck.Add(trick); familieDuck.Add(track); familieDuck.Insert(1, tick); Console.WriteLine(woerterbuch["rot"]); foreach (Person p in familieDuck) { p.gehaltErhoehen(); Console.WriteLine(p.ToString()); } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 113 Generische Collection-Typen List<T> se-rt Folie 115 Dictionary (System.Collections.Generic) ICollection<T> T this[int index] void Clear() Int Add(T o) … C# 1.01 Klasse Dictionary<TKey, TValue> int Count void CopyTo(Array a, int pos) IEnumerator GetEnumerator() … IList<T> www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Dictionary<string, Person> namensTabelle = new Dictionary<string, Person>(); namensTabelle["Donald"] = donald; namensTabelle["Tick"] = tick; namensTabelle["Trick"] = trick; namensTabelle["Track"] = track; IDictionary<TKey, TVal> if(namensTabelle.ContainsKey("Donald")) { Console.WriteLine(namensTabelle["Donald"].ToString()); } ICollection<TKey> Keys ICollection<TVal> Values void Add(TKey key, TVal value) … Dictionary<TKey, TVal> www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 114 57 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 116 58 Beispiel: Interface IComparable Übung: Windows-Forms-Applikation Personen-Objekte laden und speichern (via Serialisierung) Erfassung mit Name, Alter, Gehalt Anzeige der Liste in einer Listbox Die Methode int CompareTo(object obj) muss implementiert werden Kollektionen können nun sehr einfach sortiert werden public class Person : IComparable { // wenn this > obj --> 1 // wenn this < obj --> -1 // wenn this == obj --> 0 public int CompareTo(object obj) { Person p = (Person)obj; if (this.gehalt > p.gehalt) return 1; if (this.gehalt < p.gehalt) return -1; else return 0; List<Person> familieDuck = new List<Person>(); familieDuck.Add(donald); // ... familieDuck.Sort(); foreach (Person p in familieDuck) { p.print(); } // oder: Person[] liste = … Array.Sort(liste); } } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 117 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 119 Formular und Formularelemente Der Dialog wird durch eine Kindklasse von Form gebildet Je Formularelement gibt es ein Attribut mit definierten Eigenschaften Kapitel 8 Beispiel: Windows-Forms public partial class PersonenForm : Form { private void InitializeComponent() { this.label1 = new System.Windows.Forms.Label(); this.editName = new System.Windows.Forms.TextBox(); // ... } Form Formularelemente private System.Windows.Forms.Label label2; private System.Windows.Forms.TextBox editName; private System.Windows.Forms.NumericUpDown editAlter; // ... } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH se-rt C# 1.01 59 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 120 60 Eigenschaften der Formular-Elemente Properties Events Subjekt und Listen-Modell Selektion des Formular-Elements Das aktuell bearbeitete Personen-Objekt wird zum „Subjekt“ Die Liste der Personen-Objekte wird in einem vom Formularelement getrennten Modell - einer List<Person> - gespeichert public partial class PersonenForm : Form { private List<Person> personen = new List<Person>(); private Person subjekt = null; // ... } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 121 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 123 Subjekt lesen und anzeigen Personen-Objekt-Inhalte lesen und anzeigen private void showSubject() { editName.Text = subjekt.getName(); editAlter.Value = subjekt.getAlter(); editGehalt.Text = String.Format("{0:c}", subjekt.getGehalt()); } Kapitel 9: Unit-Test private void readSubject() { string name = editName.Text; int alter = (int)editAlter.Value; string gehaltText = editGehalt.Text; double gehalt = (double)Decimal.Parse(gehaltText); Übersicht Testprojekt Testklasse und Testattribute subjekt.setName(name); subjekt.setAlter(alter); subjekt.setGehalt(gehalt); } se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 122 61 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 62 Teststufen - Übersicht Unit-Test (1) Testgegenstand sind Komponenten, teilintegrierte Systeme oder Systeme „Testen im Kleinen“ (Liggesmeyer) Das Testobjekt beim Unit-Test ist eine Unit (=Komponente, Modul, Subsystem). Komponenten sind ein Teil einer Applikation, z. B. eine (oder mehrere) Klassen oder eine Prozedur. Im Unit-Test wird die „Unit“ gegen die Spezifikation getestet. Dazu ist eine Unit-Spezifikation erforderlich! Die Unit sollte möglichst isoliert getestet werden; die Isolierung hat dabei den Zweck, Unit-externe Einflüsse beim Test auszuschließen. Die Zuständigkeit für Unit-Tests liegt in der Regel in der Entwicklung (und nicht in der Testabteilung!) Unit-Test, Komponententest, Modultest Ö „autarke“ Komponenten werden isoliert getestet Integrationstest Ö Teilintegrierte Komponenten testen die Komponenteninteraktion Systemtest Ö Test des Gesamtsystems se-rt se-rt Bilder: Martin Glinz, Universität Zürich www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 125 Teststufen www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 127 Unit-Test (2) Unit-Test Integrationstest Systemtest Die Schnittstelle einer Unit ist in der Regel eine Programmierschnittstelle. D.h., die Ausführung der Testfälle wird in der Regel in der Programmiersprache des Moduls programmiert. Wird ein Fehler gefunden, lässt sich die Ursache in der Regel der getesteten Unit zuordnen. Es stehen Frameworks zur Verfügung: Visual Studio, www.junit.org, www.testng.org, CppUnit, TESSY, Rational Test Realtime Parametrisierte Testfälle können mit Daten aus einer externen Datenquelle befüllt werden Weitere Teststufen Ö User Acceptance Test (UAT) Ö Beta-Test Ö Abnahmetest Ö Deployment-Test Test gegen nichtfunktionale Anforderungen se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 126 63 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 128 64 Testaufbau Beispiel: Testmethoden für Bruch Beispiel Testmethoden Testtreiber [TestMethod] public void TestAddiere() { Bruch b1 = new Bruch(1, 2); Bruch b2 = new Bruch(1, 3); Bruch b3 = new Bruch(5, 6); Bruch b4 = b1 + b2; Assert.AreEqual(b3, b4); } [TestMethod] public void TestKehrwert() { Bruch b1 = new Bruch(1, 2); Bruch b2 = new Bruch(2, 1); Bruch b3 = !b2; Assert.AreEqual(b1, b3); } Der Testtreiber startet die Ausführung des Prüflings und nimmt Resultate entgegen Prüfling Stub se-rt Ein Stub (Platzhalter) ersetzt eine vom Prüfling genutzte Funktion www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 129 Unit-Test mit Visual Studio www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH Ausgangssituation Aktion Resultatsvergleich Ausgangssituation Aktion Resultatsvergleich C# 1.01 Folie 131 Unit-Test Attribute Es wird ein Test-Projekt angelegt; das Projekt mit den zu testenden Klassen wird „referenziert“ (Hinweis: die zu testenden Klassen müssen dort public sein) [ClassInitialize] Ö Wird vor Ausführung des ersten Testfalls [TestMethod] aufgerufen. Es können Initialisierungen vor Beginn des Tests vorgenommen werden. [ClassCleanup] Ö Aufräumarbeiten nach Ende aller Testfälle [TestMethod] [TestInitialize] Ö Initialisierung, die vor jedem einzelnen Testfall [TestMethod] aufgerufen werden [TestCleanup] Testklassen und Testmethoden werden über Attribute gesteuert Es ist oft hilfreich, wenn die zu testende Klasse eine EqualsMethode implementiert hat [TestClass] public class UnitTestBruch { [TestMethod] public void TestInit() { Bruch b = new Bruch(1, 2); Assert.AreEqual((double)b, 0.5, "Fehler beim Initialisieren"); } } Ö Aufräumarbeiten, die nach jedem einzelnen Testfall [TestMethod] aufgerufen werden [TestMethod] Ö Ein Testfall se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 130 65 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 132 66 Entwurfskriterium: Testbarkeit Die Isolierbarkeit einer Unit ist eine Voraussetzung für Unit-Tests Isolierbare Units entstehen bei Entwurf nicht zwangsläufig – die Isolierbarkeit muss aktiv im Entwurf herbeigeführt werden Empfehlung: Testbarkeit sollte bei Entwurfsreviews mit einbezogen werden Zur Resultatsprüfung sind oftmals spezielle Diagnose-Methoden im Prüfling erforderlich; d.h. der Unit-Test hinterläßt durchaus seine „Spuren“ an der zu testenden Unit. Einführung in die Programmiersprache C# Rainer Schmidberger [email protected] se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 se-rt Folie 133 www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Test-First-Ansatz Es werden zuerst die Testfälle (in der Regel eingebettet in den Testtreiber) implementiert und anschließend der produktive Programmcode Test-First entstammt den agilen Vorgehensweisen (Extreme Programming) Vorteile Ö QS der Anforderung Ö Automatisierung spart Aufwand Ö Der Test verliert den negativen Beigeschmack Ö Testfälle werden dokumentiert und sind reproduzierbar In der Praxis stellt eine unvollständige Unit-Spezifikation ein großes Problem dar! se-rt www.se-rt.de - © 2009 Software-Engineering Rat&Tat - TTI GmbH C# 1.01 Folie 134 67 68