1. Einführung
Stell dir vor: Du hast eine Collection... und du willst schnell das dritte, siebte oder sagen wir das nullte Element bekommen. Oder sie vertauschen. Im Array geht das easy – per Index (array[3]). Aber wie sieht's bei Collections aus? Nicht alle Collections sind gleich indexierbar!
Hier kommt das Interface IList<T> ins Spiel – ein universeller Vertrag, der von einer Collection verlangt, dass sie mit Elementen per Index umgehen kann. Kurz gesagt: Wenn du eine Collection hast, die IList<T> implementiert, kannst du easy per Index (wie beim Array) auf ihre Elemente zugreifen und sie on the fly ändern.
Analogie:
Denk an eine Bibliothekskarte: Jedes Buch hat seine eigene Nummer im Regal, und du kannst immer zum "dritten in der Reihe" gehen und es nehmen. Genau so verhält sich eine Collection, die IList<T> unterstützt.
2. Allgemeine Struktur und Methoden von IList<T>
Das Interface IList<T> ist der Held vieler Collections. Es erweitert ICollection<T> (und das wiederum IEnumerable<T>, was das Durchlaufen der Collection mit Schleifen ermöglicht) und fügt das Wichtigste hinzu: den Umgang mit dem Index.
Vererbungsdiagramm der Interfaces:
IEnumerable<T>
▲
│
ICollection<T>
▲
│
IList<T>
Wichtige Mitglieder des Interfaces IList<T>
| Mitglied | Zweck |
|---|---|
|
Element per Index holen oder setzen |
|
Index des ersten Vorkommens eines Elements finden |
|
Element an einer bestimmten Position einfügen |
|
Element per Index entfernen |
Alle anderen Mitglieder wie Add, Remove, Clear, Contains kommen aus dem Interface ICollection<T>.
Das Key-Feature: Der Indexer
Das Haupt-"Feature" von IList<T> ist der Indexer. Das ist syntactic sugar, mit dem du sowas schreiben kannst:
var myList = new List<int> { 10, 20, 30 };
int secondValue = myList[1]; // Holt 20
myList[2] = 42; // Ändert das dritte Element
3. Welche Collections implementieren IList<T>
In der Standardbibliothek von .NET unterstützen viele bekannte Strukturen das Interface IList<T>. Schauen wir uns die beliebtesten an:
| Collection | Indexierung | Beschreibung |
|---|---|---|
|
Ja | Dynamisches Array |
|
Ja | Normale Arrays sind indexierbar |
|
Ja | Wird für Data Binding verwendet |
|
Ja | Liste mit Benachrichtigungen |
|
Ja | Basisklasse für Collections |
Achtung:
LinkedList<T> und
HashSet<T>
NICHT implementieren
IList<T>, weil sie keinen schnellen Indexzugriff haben (ja,
LinkedList<T> hat kein
list[5]!).
4. Beispiele für die Nutzung von IList<T>
Holen und Setzen per Index
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
IList<string> fruits = new List<string> { "Apfel", "Banane", "Birne" };
// Zweites Element holen
string fruit = fruits[1];
Console.WriteLine(fruit); // Banane
// Drittes Element ersetzen
fruits[2] = "Orange";
Console.WriteLine(fruits[2]); // Orange
}
}
Einfügen und Entfernen per Index
fruits.Insert(1, "Kiwi"); // "Kiwi" an zweiter Stelle einfügen
// Liste jetzt: "Apfel", "Kiwi", "Banane", "Orange"
fruits.RemoveAt(0); // Erstes Element ("Apfel") entfernen
// Liste jetzt: "Kiwi", "Banane", "Orange"
Index eines Elements suchen
int index = fruits.IndexOf("Orange"); // Gibt Index (2) oder -1 zurück, falls nicht gefunden
if (index != -1)
Console.WriteLine("Orange befindet sich auf Position: " + index);
else
Console.WriteLine("Orange nicht gefunden");
5. Besonderheiten der Implementierung und typische Fehler
Wenn du mit IList<T> arbeitest, tappst du schnell in ein paar "Fallen" – vor allem, wenn du vergisst, dass die Indexierung bei null startet und die Länge der Collection die aktuelle Anzahl der Elemente ist.
Zum Beispiel, wenn du auf ein nicht existierendes Element zugreifen willst:
Console.WriteLine(fruits[100]); // IndexOutOfRangeException!
Indizes in C# sind wie Hühner: Sie fangen bei null an, nicht bei eins. Wenn die Liste 4 Elemente hat, ist der letzte gültige Index 3.
Außerdem solltest du wissen, dass nicht alle IList<T>-Implementierungen gleich schnell sind. Bei Arrays oder List<T> ist der Zugriff per Index instant (O(1)), aber wenn du deine eigene Collection auf Basis einer verketteten Liste baust und ihr irgendwie IList<T> gibst, kann die Operation langsam werden. Die Standardbibliothek macht das aber nicht.
Noch ein Punkt: Wenn du mit einem Array als IList<T> arbeitest, kannst du die Elemente ändern, aber nicht die Größe des Arrays. Methoden wie Add, Remove, Insert usw. werfen bei Arrays eine NotSupportedException.
int[] myArray = { 1, 2, 3 };
IList<int> listView = myArray; // Upcast
listView[0] = 42; // Funktioniert!
listView.Add(99); // Wirft NotSupportedException
6. Praktische Anwendung und wozu das Ganze?
In echten Projekten ist fast jede zweite Collection irgendwas, das IList<T> implementiert, weil es einfach praktisch ist, schnell per Nummer auf Elemente zuzugreifen, sie zu ändern, einzufügen oder zu löschen. Zum Beispiel:
- Interface-Properties in ViewModels von WPF oder WinForms, an die UI-Element-Listen gebunden werden.
- Implementierung von Sortier-, Such- oder Permutationsalgorithmen, wo Indexzugriff gebraucht wird.
- Import-/Export-Module, die mit einer dynamischen Objektliste arbeiten.
Im Vorstellungsgespräch ist die Frage nach den Unterschieden zwischen IEnumerable<T>, ICollection<T> und IList<T> ein Klassiker. Wenn du weißt, wofür jede Ebene zuständig ist, kannst du dem Interviewer easy erklären, warum HashSet<T> kein IList<T> implementiert (weil Einzigartigkeit wichtiger ist als Reihenfolge und Indizes!).
GO TO FULL VERSION