# 8 Auflistungsklassen (Collections) Ein charakteristisches Merkmal der Arrays ist die freie Verfügbarkeit ihrer Indizes. Sie können ein Element einem Array an einer x-beliebigen Position hinzufügen – unabhängig davon, ob der Index bereits von einem anderen Element belegt ist oder nicht. Wird ein Element aus einem Array entfernt, bleibt ein unbesetzter Index zurück. Ein Array ist somit ein statischer Pool freier und belegter Elementpositionen ohne die Fähigkeit, sich dynamisch an Änderungen anpassen zu können. An dieser Stelle treten Klassen in Erscheinung, die ähnlich den Arrays als Container meist typgleicher Elemente dienen. Im Unterschied zu den herkömmlichen Arrays arbeiten diese Klassen jedoch dynamisch: Sie enthalten keine »leeren« Indizes, sondern vergrößern oder verkleinern ihre Kapazität entsprechend der Anzahl der Einträge. Ganz allgemein werden diese Klassen als Collections, als Auflistungen oder ganz einfach nur als Listen bezeichnet. Jede Klasse unterscheidet sich von der anderen durch besondere Fähigkeiten und Charakteristika – sei es die interne Verwaltung der Objekte, der Zugriff auf die Einträge oder die Geschwindigkeit, mit der innerhalb einer Liste nach einem bestimmten Eintrag gesucht werden kann. Leider wurden die Generics erst mit dem .NET Framework 2.0 eingeführt. Wäre dies bereits mit der Version 1.0 geschehen, wären uns viele Klassen und Interfaces erspart geblieben. So aber müssen wir bereits an dieser Stelle zwei Gruppen von Auflistungen unterscheiden: die nichtgenerischen Listen, die zum Namespace System.Collections gehören die generischen Listen des Namespace Systems.Collections.Generics Wenn möglich, sollten Sie auf die generischen Collections zurückgreifen, und zwar der Typsicherheit wegen. Auch wenn das Coding der Generics im Allgemeinen etwas gewöhnungsbedürftig ist, ist am Ende die Handhabung generischer Listen deutlich einfacher, und sie sind sogar schneller als ihre nichtgenerischen Pendants. Nichtsdestotrotz werden wir natürlich auch die nichtgenerischen Listen hier exemplarisch behandeln, schließlich werden Sie im .NET Framework auf unzählige Klassen stoßen, die nach genau diesem Prinzip entwickelt worden sind. ## 8.1 Die Listen des Namespace »System.Collections« Damit Sie die Namen einiger wichtiger Auflistungen schon einmal gehört haben, seien sie hier aufgeführt: ArrayList Hashtable Queue Stack SortedList StringCollection Diese Klassen, die alle zum Namespace System.Collections gehören, unterscheiden sich in den Methoden, mit denen der Zugriff auf die Elemente erfolgt, darin, wie die Elemente im Speicher verwaltet werden, und dadurch, welche Operationen sich darauf ausführen lassen. Jede Klasse hat dabei ihre eigene Charakteristik. Da sie zwei typische Vertreter vieler anderer Klassen im .NET Framework sind, wollen wir uns einen Überblick über die Charakteristik der beiden Klassen ArrayList und Hashtable verschaffen und die wesentlichsten Unterscheidungsmerkmale herausarbeiten. #### Die Klasse »ArrayList« ArrayList ähnelt außerordentlich einem klassischen Array. Im Gegensatz zu einem Array ist ein ArrayList-Objekt aber dynamisch. Sie können so lange Objekte zur Liste hinzufügen, bis dem Speicher regelrecht die Puste ausgeht. Der Zugriff auf ein Element einer ArrayList erfolgt über die Angabe des entsprechenden Index. #### Die Klasse »Hashtable« Die Klasse Hashtable beschreibt eine Liste von Elementen, die im Gegensatz zur ArrayList nicht durch einen Index verwaltet werden, sondern durch ein Schlüssel-Werte-Paar. Der Vorteil eines Hashtable-Objekts ist, dass innerhalb der Liste sehr schnell nach bestimmten Objekten gesucht werden kann. Der Name rührt daher, dass für die Verwaltung der Elemente ein Hashcode für den Schlüssel verwendet wird. Ein Hashcode ist ein Wert, der aus den Daten eines Objekts gebildet wird und somit für gleiche Objekte gleich ist. Der Zugriff auf ein Element in dieser Liste erfolgt über den Schlüsselwert, der grundsätzlich ein beliebiges Objekt sein kann. In der Praxis wird dazu meist eine Zeichenfolge benutzt. ### 8.1.1 Die elementaren Schnittstellen der Auflistungsklassen Die Grundfunktionalität aller Auflistungen lässt sich auf elementare Methoden zurückführen. Es ist deshalb nicht verwunderlich, dass die Gemeinsamkeiten durch Schnittstellen beschrieben werden, die von den Auflistungsklassen implementiert werden. Im Kern handelt es sich dabei um folgende Schnittstellen: IEnumerable ICollection IDictionary IList Die beiden zuerst aufgeführten Schnittstellen IEnumerable und ICollection werden von allen Standardauflistungsklassen implementiert. Sie sichern Verhaltensweisen, über die jede Auflistungsklasse verfügt. Das elementare Verhalten einer Auflistungsklasse wird durch die Implementierung der Schnittstellen IList und IDictionary beschrieben: IList ist dabei das Interface für die indexbasierten Auflistungen, IDictionary die Schnittstelle der Auflistungen, die auf Schlüssel-Wertepaaren basieren. Ohne zu sehr in die Details abzutauchen, wollen wir uns nun ein weniger genauer die vier genannten Schnittstellen ansehen. #### Die Schnittstelle »IEnumerable« IEnumerable ermöglicht es, eine Liste in einer foreach-Schleife zu durchlaufen, und weist nur die Methode GetEnumerator auf, die ein Objekt zurückliefert, das die Schnittstelle IEnumerator implementiert. Dieser Enumerator verfügt über die Fähigkeit, eine Auflistung elementweise zu durchlaufen. Damit gleicht dieses Objekt einem Positionszeiger, dem drei Methoden eigen sind: Current, MoveNext und Reset. Der Enumerator positioniert sich standardmäßig vor dem ersten Eintrag einer Auflistung. Um ihn auf den ersten Eintrag und anschließend auf alle Folgeeinträge zeigen zu lassen, muss die Methode MoveNext ausgeführt werden. Mit Current wird auf den Eintrag zugegriffen, auf den der Enumerator aktuell zeigt. Reset setzt den Enumerator an seine Ausgangsposition zurück, also vor den ersten Eintrag. Alle Collections implementieren die Schnittstelle IEnumerable, sodass auch alle Auflistungen in einer foreach-Schleife durchlaufen werden können. #### Die Schnittstelle »ICollection« Die Schnittstelle ICollection stellt allen Auflistungen die Eigenschaften Count, IsSynchronized und SyncRoot zur Verfügung, und darüber hinaus auch die Methode CopyTo. Count liefert dabei die die Anzahl der Elemente einer Auflistung zurück, die Methode CopyTo kopiert die Elemente einer Auflistung in ein Array. Auflistungen sind kritisch hinsichtlich des gleichzeitigen Zugriffs mehrerer Threads. Um diesem Umstand Rechnung zu tragen, wird die Methode Synchronized bereitgestellt. Die Eigenschaft IsSynchronized gibt an, ob die Auflistung synchronisiert ist. Es ist daher nicht verwunderlich, dass praktisch alle Standardauflistungen die Schnittstelle ICollection implementieren. #### Die Schnittstelle »IList« Auflistungen, die IList implementieren, können ihre Elemente über Indizes verwalten. Das beste Beispiel hierfür dürfte die Klasse ArrayList sein, aber auch eine große Anzahl weiterer, häufig steuerelementspezifischer Auflistungen gehört zu dieser Gruppe, unter anderem auch die Klasse Array. Die wichtigsten Methoden, die von IList zur Verfügung gestellt werden, sind Add, Clear, Contains, Insert, IndexOf und Remove. Sie werden Collections, die diese Methoden aufweisen, überall im .NET Framework begegnen: Sei es innerhalb der WinForm-API oder bei verschiedenen Klassen von ADO.NET. #### Die Schnittstelle »IDictionary«