Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort zur 5. Auflage
1 Allgemeine Einführung in .NET
2 Grundlagen der Sprache C#
3 Klassendesign
4 Vererbung, Polymorphie und Interfaces
5 Delegates und Ereignisse
6 Weitere .NET-Datentypen
7 Weitere Möglichkeiten von C#
8 Auflistungsklassen (Collections)
9 Fehlerbehandlung und Debugging
10 LINQ to Objects
11 Multithreading und die Task Parallel Library (TPL)
12 Arbeiten mit Dateien und Streams
13 Binäre Serialisierung
14 Einige wichtige .NET-Klassen
15 Projektmanagement und Visual Studio 2010
16 XML
17 WPF – Die Grundlagen
18 WPF-Containerelemente
19 WPF-Steuerelemente
20 Konzepte der WPF
21 Datenbindung
22 2D-Grafik
23 ADO.NET – verbindungsorientierte Objekte
24 ADO.NET – Das Command-Objekt
25 ADO.NET – Der SqlDataAdapter
26 ADO.NET – Daten im lokalen Speicher
27 ADO.NET – Aktualisieren der Datenbank
28 Stark typisierte DataSets
29 LINQ to SQL
30 Weitergabe von Anwendungen
Stichwort

Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Visual C# 2010 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2010

Visual C# 2010
geb., mit DVD
1295 S., 49,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1552-7
Pfeil 8 Auflistungsklassen (Collections)
Pfeil 8.1 Die Listen des Namespace »System.Collections«
Pfeil 8.1.1 Die elementaren Schnittstellen der Auflistungsklassen
Pfeil 8.2 Die Klasse »ArrayList«
Pfeil 8.2.1 Einträge hinzufügen
Pfeil 8.2.2 Datenaustausch zwischen einem Array und einer ArrayList
Pfeil 8.2.3 Die Elemente einer ArrayList sortieren
Pfeil 8.2.4 Sortieren von Arrays mit »ArrayList.Adapter«
Pfeil 8.3 Die Klasse »Hashtable«
Pfeil 8.3.1 Methoden und Eigenschaften der Schnittstelle »IDictionary«
Pfeil 8.3.2 Beispielprogramm zur Klasse »Hashtable«
Pfeil 8.4 Die Klassen »Queue« und »Stack«
Pfeil 8.4.1 Die »Stack«-Klasse
Pfeil 8.5 Objektauflistungen im Überblick
Pfeil 8.6 Generische Auflistungsklassen
Pfeil 8.6.1 Die Interfaces der generischen Auflistungsklassen
Pfeil 8.6.2 Die generische Auflistungsklasse »List<T>«
Pfeil 8.7 Eigene Auflistungen mit »yield« durchlaufen


Galileo Computing - Zum Seitenanfang

8.6 Generische Auflistungsklassen Zur nächsten ÜberschriftZur vorigen Überschrift

Ein ganz wesentlicher Nachteil der Auflistungen aus dem Namespace System.Collections ist, dass sie allgemein gehalten sind und immer den Typ Object verwalten. Damit können Sie in einem Auflistungsobjekt alles speichern, von einem Integer über einen Stream bis hin zur Datenbanktabelle. Wenn Sie nicht wissen, welche Typen von der Auflistung verwaltet werden, haben Sie praktisch keine Chance, die Elemente auszuwerten. Bedenken Sie, dass Sie jedes Element der Auflistung zuerst in den richtigen Typ konvertieren müssen, um dessen spezifische Eigenschaften nutzen zu können.

Generische Auflistungsklassen haben diesen Nachteil nicht. Sie sind auf einen bestimmten Typ gedrillt. Das bedeutet, dass Sie vorschreiben, welche Typen von der Collection verwaltet werden sollen. Der Code wird einfacher und besser lesbar, weil Sie meistens keine Konvertierung vornehmen müssen, um auf die spezifischen Member der verwalteten Elemente zuzugreifen.

Im Wesentlichen habe ich Ihnen in diesem Kapitel zwei nichtgenerische Auflistungsklassen vorgestellt: die indexbasierte ArrayList und das Dictionary Hashtable. Beide haben einen generischen Gegenspieler in List<T> und Dictionary<TKey, TValue>. In diesem Abschnitt werde ich Ihnen List<T> vorstellen. Anhand des hier Gesagten erübrigt sich eine weitere Vertiefung der Klasse Dictionary<TKey, TValue>.


Galileo Computing - Zum Seitenanfang

8.6.1 Die Interfaces der generischen Auflistungsklassen Zur nächsten ÜberschriftZur vorigen Überschrift

Sie wissen, dass alle nichtgenerischen Auflistungsklassen die beiden Schnittstellen ICollection und IEnumerable implementieren. Zudem implementieren die indexbasierten Auflistungen die Schnittstelle IList und alle Schlüssel-Wert-Paar-Auflistungen die Schnittstelle IDictionary. Haben wir es mit generischen Auflistungsklassen zu tun, sind auch diese Schnittstellen generisch. Somit handelt es sich um

  • IEnumerable<T>
  • ICollection<T>
  • IDictionary<TKey, TValue>
  • IList<T>

Eine genauere Beschreibung dieser Interfaces ist nicht notwendig, da sie sich in ihrem elementaren Verhalten nicht von den nichtgenerischen unterscheiden.


Galileo Computing - Zum Seitenanfang

8.6.2 Die generische Auflistungsklasse »List<T>« topZur vorigen Überschrift

Im Großen und Ganzen ist kein wesentlicher Unterschied zwischen den Methoden und Eigenschaften einer ArrayList und List<T> festzustellen. Sie fügen mit Add oder AddRange Objekte hinzu, Sie löschen Auflistungselemente mit Remove oder RemoveAt, Sie besorgen sich den Index eines Elements mit IndexOf. Natürlich sind alle Methoden generisch geprägt, also auf den Typ hin spezialisiert, den Sie bei der Instanziierung der Klasse angegeben haben. Konzentrieren wir uns daher sofort auf ein Beispielprogramm.

Sortieren einer indexbasierten Collection

In Abschnitt 8.3.3 habe ich Ihnen im Beispielprogramm IComparerSample den Einsatz von Vergleichsklassen vorgestellt, um die Elemente einer ArrayList nach eigenen Kriterien zu sortieren. Ausgangspunkt war die Klasse Person mit den beiden Feldern Name und Wohnort. In der Anwendung wurden mehrere Person-Objekte einem ArrayList-Objekt hinzugefügt und konnten entweder nach Wohnort oder Name sortiert an der Konsole ausgegeben werden. Vielleicht erinnern Sie sich noch, dass eine verhältnismäßig komplexe Konvertierung notwendig war, um den Rückgabewert des Vergleichs zu bilden. In der Vergleichsklasse NameComparer sah die Anweisung wie folgt aus:


return ((Person)x).Name.CompareTo(((Person)y).Name);

Mit der generischen Auflistungsklasse IList<T> geht alles viel einfacher. Person-Objekte werden nun in einem Objekt von diesem Typ direkt verwaltet:


List<Person> liste = new List<Person>();

Damit gilt die Collection als streng typisiert: Sie verwaltet nur Objekte vom Typ Person und wird strikt andere Typen abweisen.

Unser Ziel sei es auch in diesem Beispiel, entweder nach Name oder Wohnort sortieren zu können. So wie die Klasse ArrayList bietet auch List<T> eine Methode Sort an, die das gewährleistet. Schauen wir uns deren Definition an:


public void Sort(IComparer<T> comparer)

Im Gegensatz zur Methode Sort der ArrayList wird nun ein Objekt erwartet, das eine generische Schnittstelle implementiert. Sehen wir uns doch auch noch die Definition der Schnittstellenmethode an:


public interface IComparer<T> {
  int Compare(T x, T y);
}

Compare vergleicht anscheinend zwei Objekte miteinander, deren Typ durch den Typparameter T beschrieben wird. Bezogen auf unser Beispiel bedeutet das, den Typparameter T durch Person zu ersetzen. Damit werden die Referenzen, die der Methode Compare als Argumente übergeben werden, vor deren Eintritt in den Code der Methode gefiltert.

Diese Erkenntnis wollen wir nun auch umsetzen. Dazu sind die beiden Klassen NameComparer und WohnortComparer im Vergleich zur ersten Version des Beispielprogramms ein wenig zu ändern – besser gesagt, zu vereinfachen. Anhand der Klasse WohnortComparer sei dies gezeigt.


// Vergleichsklasse - Kriterium 'Wohnort'
class WohnortComparer : IComparer<Person> {
  public int Compare(Person x, Person y) {
    // prüfen auf null-Übergabe
    if (x == null && y == null) return 0;
    if (x == null) return 1;
    if (y == null) return -1; 
    // Vergleich
    return x.Wohnort.CompareTo(y.Wohnort);
  }
}

Auch wenn der Umgang mit generischen Klassen und Schnittstellen im ersten Moment ein wenig gewöhnungsbedürftig erscheint, ist der Vergleich zweier Objekte deutlich einfacher geworden, weil keine Konvertierung mehr notwendig ist. Das ist darauf zurückzuführen, dass wir durch Einsatz der generischen Schnittstellenmethode garantieren können, ausschließlich Person-Objekte zu vergleichen. Zudem können wir uns auch die Typüberprüfung sparen, die in der Ursprungsversion unseres Beispiels noch notwendig war.

Zum Schluss folgt hier der gesamte Code des Beispiels:


// -----------------------------------------------------------
// Beispiel: ...\Kapitel 8\GenericListSample
// -----------------------------------------------------------
class Program {
  static void Main(string[] args) {
    List<Person> liste = new List<Person>();
    // generische Liste füllen
    Person pers1 = new Person("Meier", "Berlin");
    liste.Add(pers1);
    Person pers2 = new Person("Arnhold", "Köln");
    liste.Add(pers2);
    Person pers3 = new Person("Graubär", "Aachen");
    liste.Add(pers3); 
    // nach Wohnorten sortieren
    liste.Sort(new WohnortComparer());
    Console.WriteLine("Liste nach Wohnorten sortiert");
    ShowSortedList(liste);
    // nach Namen sortieren
    liste.Sort(new NameComparer());
    Console.WriteLine("Liste nach Namen sortiert");
    ShowSortedList(liste);
    Console.ReadLine();
  }
  static void ShowSortedList(IList<Person> liste) {
    foreach (Person temp in liste) {
      Console.Write("Name = {0,-12}", temp.Name);
      Console.WriteLine("Wohnort = {0}", temp.Wohnort);
    }
    Console.WriteLine();
  }
}
// Vergleichsklasse - Kriterium 'Wohnort'
class WohnortComparer : IComparer<Person> {
  public int Compare(Person x, Person y) {
    // prüfen auf null-Übergabe
    if (x == null && y == null) return 0;
    if (x == null) return 1;
    if (y == null) return -1; 
    // Vergleich
    return x.Wohnort.CompareTo(y.Wohnort);
  }
}
// Vergleichsklasse - Kriterium 'Name'
class NameComparer : IComparer<Person> {
  public int Compare(Person x, Person y) {
    // prüfen auf null-Übergabe
    if (x == null && y == null) return 0;
    if (x == null) return 1;
    if (y == null) return -1; 
    // Vergleich
    return x.Name.CompareTo(y.Name);
  }
}
class Person {
  public string Name;
  public string Wohnort;
  public Person(string name, string ort) {
    Name = name;
    Wohnort = ort;
  }
}

Vergleiche mithilfe des Delegates »Comparison<T>«

Im Vergleich zur Klasse ArrayList hat die Klasse List<T> noch eine weitere interessante Überladung der Methode Sort, die es uns gestattet, den Code noch kürzer und intuitiver zu schreiben. Sehen wir uns die Definition der Methode an.


public void Sort(Comparison<T> comparison)

Die Überladung erwartet die Übergabe eines Comparison<T>-Objekts. Dabei handelt es sich um ein Delegate, das auf die Methode zeigt, die den Vergleich zweier T-Objekte durchführt und das Resultat des Vergleichs an den Aufrufer liefert. Das Delegate ist wie folgt definiert:


public delegate int Comparison<T>(T x, T y);

Bezogen auf das Beispielprogramm GenericListSample können wir auf die beiden Vergleichsklassen verzichten. Wir stellen stattdessen zwei Methoden bereit, die dasselbe zu leisten vermögen. Das folgende Beispielprogramm zeigt, wie Sie diese Überladung von Sort einsetzen können.


// -----------------------------------------------------------
// Beispiel: ...\Kapitel 8\GenericListSample
// -----------------------------------------------------------
class Program {
  static void Main(string[] args) {
    List<Person> arrList = new List<Person>();
    ... 
    // nach Wohnorten sortieren
    arrList.Sort(CompareByWohnort);
    Console.WriteLine("Liste nach Wohnorten sortiert");
    ShowSortedList(arrList); 
    // nach Namen sortieren
    arrList.Sort(CompareByName);
    Console.WriteLine("Liste nach Namen sortiert");
    ShowSortedList(arrList);
    Console.ReadLine();
  }
  public static int CompareByName(Person x, Person y) {
    // prüfen auf null-Übergabe
    if (x == null && y == null) return 0;
    if (x == null) return 1;
    if (y == null) return -1; 
    // Vergleich
    return x.Name.CompareTo(y.Name);
  }
  public static int CompareByWohnort(Person x, Person y) {
    // prüfen auf null-Übergabe
    if (x == null && y == null) return 0;
    if (x == null) return 1;
    if (y == null) return -1; 
    // Vergleich
    return x.Wohnort.CompareTo(y.Wohnort);
  }
  static void ShowSortedList(IList<Person> liste) { ... }
}

Verschachtelte generische Klassen

Nun kommen wir zum zweiten neu aufgelegten Beispiel. Es handelt sich hierbei um die (Fußball-)Mannschaft, die als Collection ausgebildet ist und Objekte vom Typ Spieler verwalten soll. Das Beispiel hatten wir in Abschnitt 7.4, »Indexer«, es soll aber nun um eine weitere Anforderung ergänzt werden. Dazu sollen mehrere Mannschaften eine gemeinsame Liga bilden, die ebenfalls eine Collection ist, ihrerseits aber nur Mannschaften verwaltet.

Zur Lösung der Aufgabenstellung können wir auch in diesem Beispiel auf die Klasse List<T> zurückgreifen.


// -----------------------------------------------------------
// Beispiel: ...\Kapitel 8\Bundesliga
// -----------------------------------------------------------
class Program {
  static void Main(string[] args) {
    // 1. Mannschaft
    Mannschaft s04 = new Mannschaft("Schalke 04");
    s04.Add(new Spieler("Müller", 34, SpielPosition.Stürmer));
    s04.Add(new Spieler("Fischer", 23,SpielPosition.Mittelfeldspieler));
    s04.Add(new Spieler("Meier", 29, SpielPosition.Torwart)); 
    // 2. Mannschaft
    Mannschaft werder = new Mannschaft("Werder Bremen");
    werder.Add(new Spieler("Graf", 37, SpielPosition.Mittelfeldspieler));
    werder.Add(new Spieler("Weide", 31, SpielPosition.Torwart));
    werder.Add(new Spieler("Maradona", 28, SpielPosition.Stürmer)); 
    // Bundesliga definieren
    List<List<Spieler>> Bundesliga = new List<List<Spieler>>();
    Bundesliga.Add(s04);
    Bundesliga.Add(werder); 
    // Ausgabe aller Mannschaften und deren Spieler
    foreach (Mannschaft tempTeam in Bundesliga) {
      Console.WriteLine(tempTeam.Vereinsname);
      foreach (Spieler spieler in tempTeam) {
        Console.WriteLine("{0,-10}{1,-3}{2}",
                spieler.Name, spieler.Alter, spieler.Position);
      }
      Console.WriteLine();
    }
    Console.ReadLine();
  }
}
// ------ Spieler --------
class Spieler {
  public string Name;
  public int Alter;
  public SpielPosition Position;
  public Spieler(string name, int alter, SpielPosition position) {
    Name = name;
    Alter = alter;
    this.Position = position;
  }
}
// ------ Mannschaft ---------
class Mannschaft : List<Spieler> {
  public string Vereinsname;
  public Mannschaft(string verein) {
    Vereinsname = verein;
  }
}
// ----- diverse Positionen -----
enum SpielPosition {
  Torwart,
  Verteidiger,
  Mittelfeldspieler,
  Stürmer
}

Da eine Mannschaft nur aus Spielern besteht und eine Liga ihrerseits nur aus Mannschaften, drängt sich der Typ List<T> auch in diesem Beispiel geradezu auf. Im Fall der Mannschaft ist der Typparameter dann natürlich Spieler, eine Klasse, die in der Anwendung definiert ist. Um eine Mannschaft zu erzeugen, würde es durchaus genügen, mit


List<Spieler> Schalke04 = new List<Spieler>();

ein Objekt zu erzeugen. Diese Mannschaft hätte dann jedoch keine spezifischen Eigenschaften, und der Vereinsname soll doch mindestens vorhanden sein, oder? Daher ist eine Klasse Mannschaft definiert, die von List<Spieler> abgeleitet ist und in einem Feld den Vereinsnamen als Zeichenfolge speichern kann.

Die Bundesliga ist als verschachtelter generischer Typ ausgebildet. Es handelt sich dabei um eine Auflistung, die selbst nur Mannschaften, also Objekte vom Typ List<Spieler>, verwalten kann.


List<List<Spieler>> Bundesliga = new List<List<Spieler>>();

Eine solche Verschachtelung ist möglich, weil List<Spieler> ganz präzise einen bestimmten Typ definiert, der selbst den generischen Typparameter der Klasse List<T> ersetzt. Solche Verschachtelungen können Sie in praktisch beliebiger Tiefe codieren.

Der Collection-Initialisierer, den Sie weiter oben im Zusammenhang mit den nichtgenerischen Auflistungen bereits kennengelernt haben, kann auch von einer generischen Collection genutzt werden. So hätten wir auch die erste Mannschaft folgendermaßen initialisieren können:


Mannschaft s04 = new Mannschaft("Schalke 04"){
  new Spieler("Müller", 34, SpielPosition.Stürmer),
  new Spieler("Fischer", 23, SpielPosition.Mittelfeldspieler),
  new Spieler("Meier", 29, SpielPosition.Torwart)
};



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
<< zurück
  Zum Katalog
Zum Katalog: Visual C# 2010

Visual C# 2010
Jetzt bestellen


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

 Buchempfehlungen
Zum Katalog: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Katalog: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Katalog: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Katalog: C++ Handbuch






 C++ Handbuch


Zum Katalog: C/C++






 C/C++


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2010
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

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

Cookie-Einstellungen ändern