CodeGym /Kurse /C# SELF /Kollektionen: OrderedDicti...

Kollektionen: OrderedDictionary und ReadOnlySet

C# SELF
Level 34 , Lektion 1
Verfügbar

1. Kollektion OrderedDictionary

.NET hatte schon immer eine fette Standardbibliothek, aber im Alltag als Entwickler gab's immer wieder Kompromisse: Man will ein Dictionary, das sich die Reihenfolge merkt, oder braucht ein Set mit unveränderlichen, einzigartigen Werten. Vor .NET 9 musste man auf externe Bibliotheken zurückgreifen oder sich selbst was basteln (manche haben sogar GitHub aufgemacht und OrderedDictionary einfach kopiert – pssst, wir verraten's niemandem).

Mit .NET 9 gibt's jetzt neue generische Kollektionen – endlich Schluss mit Workarounds! Lass uns die zwei praktischsten davon genauer anschauen: OrderedDictionary<TKey, TValue> und ReadOnlySet<T>.

1. Was ist OrderedDictionary?

OrderedDictionary ist ein Hybrid aus Dictionary und Liste. Er speichert "Key-Value"-Paare wie ein normales Dictionary<TKey, TValue>, garantiert aber, dass die Reihenfolge der Elemente der Reihenfolge entspricht, in der sie hinzugefügt wurden. Das ist besonders wichtig, wenn du Elemente in genau der Reihenfolge durchgehen willst, wie der User sie eingegeben hat, oder wenn die Reihenfolge für die Business-Logik zählt: z.B. beim Drucken von Reports, Serialisieren von Daten, Generieren von Konfigurationen.

Analogie

Wenn ein normales Dictionary wie ein Schrank mit vielen Fächern ist, wo du Sachen schnell rein- und rauslegen kannst, ohne auf die Reihenfolge zu achten, dann ist OrderedDictionary wie ein ordentlicher Schrank mit Schubladen. Da liegt alles schön sortiert, und du weißt immer, was zuerst und was zuletzt reingekommen ist.

2. Hauptunterschied zu Dictionary

  • Dictionary: Die Reihenfolge der Elemente ist nicht garantiert (auch wenn es manchmal so aussieht – glaub's nicht, das ist nur Zufall!).
  • OrderedDictionary: Die Elemente bleiben genau in der Reihenfolge, wie sie hinzugefügt wurden.

3. Syntax und wichtigste Methoden

Hier ein einfaches Beispiel:


using System.Collections.Generic;

var od = new OrderedDictionary<string, int>();
od.Add("Ivan", 5);
od.Add("Svetlana", 8);
od.Add("Alex", 3);

// Durchlaufen in der Reihenfolge der Hinzufügung:
foreach (var pair in od)
{
    Console.WriteLine($"{pair.Key}: {pair.Value}");
}

Ausgabe:

Ivan: 5
Svetlana: 8
Alex: 3

Wenn du das gleiche Beispiel mit einem normalen Dictionary machst, ist die Reihenfolge meistens anders. Mit OrderedDictionary ist sie immer so, wie du sie hinzugefügt hast.

OrderedDictionary implementiert die gleichen Interfaces wie ein normales Dictionary:

  • IDictionary<TKey, TValue>
  • IReadOnlyDictionary<TKey, TValue>
  • IEnumerable<KeyValuePair<TKey, TValue>>

4. Zugriff per Index und per Key

Das Besondere: OrderedDictionary hat einen Indexer sowohl für den Key als auch für den numerischen Index!


// Nach Name (Key):
int svetlanaScore = od["Svetlana"]; // 8

// Nach Index:
var firstEntry = od.ElementAt(0); // KeyValuePair<string, int>("Ivan", 5)

5. Aktualisieren und Entfernen

Wenn du ein neues Element mit einem schon existierenden Key hinzufügst, gibt's eine Exception. Wenn du den Wert ersetzen willst – nimm den Indexer:

od["Ivan"] = 10; // Ändert den existierenden, Reihenfolge bleibt gleich

Löschen geht sowohl per Key als auch per Index:


od.Remove("Svetlana");
od.RemoveAt(0);      // löscht "Ivan"

6. Visualisierung der Struktur


flowchart LR
    A("0: Ivan - 5")
    B("1: Svetlana - 8")
    C("2: Alex - 3")
    A --> B --> C
Jeder Knoten ist ein Key-Value-Paar, und die Pfeile zeigen die Reihenfolge der Hinzufügung.

7. Stolperfallen und Fehler

Viele Entwickler versuchen, Dictionary<TKey, TValue> zu benutzen und hoffen auf eine feste Reihenfolge – das ist eine Falle! Selbst wenn es bei manchen Daten klappt, kann es beim nächsten Mal anders sein (vor allem bei .NET-Updates oder auf einer anderen Plattform).

Bei OrderedDictionary sind manche Operationen (z.B. Einfügen oder Löschen in der Mitte) minimal langsamer als beim normalen Dictionary, weil die Reihenfolge gespeichert wird – aber für die meisten Anwendungsfälle überwiegen die Vorteile.

Wenn du oft per Index suchst – dann ist OrderedDictionary genau richtig. Wenn du nur schnellen Zugriff per Key brauchst und die Reihenfolge egal ist – nimm das normale Dictionary.

8. Praxisbeispiel für eine App

Angenommen, in unserer Mitarbeiter- und Abteilungs-App brauchen wir jetzt einen Report, in dem die Mitarbeiter in der Reihenfolge ausgegeben werden, wie sie hinzugefügt wurden:


var employeeScores = new OrderedDictionary<string, int>();
employeeScores.Add("Pjotr", 100);
employeeScores.Add("Anna", 150);
employeeScores.Add("Viktoria", 80);

// Jetzt ist der Report immer in der richtigen Reihenfolge:
foreach (var pair in employeeScores)
{
    Console.WriteLine($"{pair.Key}: {pair.Value} Punkte");
}

2. Kollektion ReadOnlySet<T>

1. Was ist ReadOnlySet?

ReadOnlySet<T> ist eine unveränderliche (immutable) Menge von einzigartigen Werten. Früher musste man, um ein "read-only set" zu bauen, eine Kopie mit .ToHashSet() zurückgeben oder einen eigenen Wrapper schreiben. Jetzt gibt's eine Kollektion, in die man nach der Erstellung nichts mehr hinzufügen oder löschen kann. Das macht den Code sicherer und verhindert versehentliche Fehler durch Änderungen von außen.

Analogie

Das ist wie ein Notizbuch, in das du einzigartige Namen schreibst und... dann die Seiten laminierst. Niemand kann mehr was reinschreiben, rausreißen oder ändern.

2. Erstellen eines ReadOnlySet

Am einfachsten erstellst du eine unveränderliche Menge mit einer Extension-Methode:


var colors = new[] { "Rot", "Grün", "Blau", "Grün" };
var readOnlyColors = colors.ToReadOnlySet();

// Jetzt sind hier nur einzigartige Werte drin und man kann nichts mehr ändern:
foreach (var color in readOnlyColors)
    Console.WriteLine(color);

Ausgabe:

Rot
Grün
Blau

Du kannst auch den direkten Konstruktor nehmen (wenn du willst):


var set = new ReadOnlySet<int>(new[] {1, 2, 2, 3, 5, 1}); // Es bleibt trotzdem 1,2,3,5

ReadOnlySet in den Microsoft Docs

3. Wichtige Eigenschaften und Methoden

  • Nur Lesen (immutable)
  • Count – Anzahl der Elemente
  • Contains(item) – Prüft, ob ein Element drin ist
  • Unterstützt LINQ-Queries (IEnumerable<T>)
  • Schnelle Suche, aber kein Hinzufügen, Löschen oder Clear

Beispiel:


if (readOnlyColors.Contains("Rot"))
    Console.WriteLine("Rot ist in der Liste!");

Das hier geht nicht:


// Compiler-Fehler!
readOnlyColors.Add("Gelb");

4. Wo ist das nützlich?

Sehr oft willst du nach außen eine Menge zurückgeben, aber niemand soll sie aus Versehen (oder absichtlich) ändern können. Zum Beispiel:

  • Liste der unterstützten User-Rollen zurückgeben
  • Liste erlaubter Dateiendungen
  • Liste von einzigartigen Konfigurationsparametern, die nicht geändert werden dürfen

Beispiel in unserer App: Angenommen, es gibt eine Liste erlaubter Abteilungen:


public static ReadOnlySet<string> Departments { get; } =
    new[] { "Personal", "Entwicklung", "Buchhaltung" }.ToReadOnlySet();

Jetzt kann niemand die Abteilungsliste von außen manipulieren.

5. Visualisierung: Unterschied zu normalem HashSet


graph LR
    A[HashSet] -- Add/Remove/Contains --> B((Elemente))
    C[ReadOnlySet] -- Only Contains --> D((Elemente))
HashSet kann man ändern, ReadOnlySet – niemals!

3. OrderedDictionary vs. ReadOnlySet: Vergleichstabelle

Kollektion Speichert Paare? Garantiert Reihenfolge Veränderbar Suche per Key Suche per Index Szenarien
OrderedDictionary Ja, "Key-Value" Ja Ja Ja Ja Karten, Einstellungen, Reports
ReadOnlySet Nein, nur Werte Nein Nein Ja Nein Sichere Mengen, Konstanten
HashSet Nein, nur Werte Nein Ja Ja Nein Mengen, die man ändern will
Dictionary Ja, "Key-Value" Nein Ja Ja Nein Karten ohne Reihenfolge-Anforderung
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION