1. Einführung
Wir haben bereits mit Kollektionen gearbeitet. Ohne sie geht in der Programmierung wie im Leben nichts. Stell dir vor, du machst eine To-Do-Liste für den Tag: Lebensmittel kaufen, Arzt anrufen, Bestellung abholen. Wahrscheinlich legst du nicht für jede Aufgabe ein eigenes Notizbuch an. Viel einfacher und logischer ist es, alle Aufgaben in eine Liste zu schreiben.
Genauso in der Programmierung: wenn die Anzahl der Objekte wächst — Benutzer, Bestellungen, Nachrichten — erstellen wir nicht für jedes eine eigene Variable. Stattdessen benutzen wir Kollektionen: Listen, Dictionaries, Sets. Das macht es einfach, Gruppen von Daten zu speichern, zu iterieren und zu verarbeiten.
Alltags-Szenarien:
- Speicherung und Austausch von Daten zwischen Anwendungen: deine Buchsammlung kann von einem Programm ins andere migrieren.
- Caching von Datensätzen auf der Festplatte.
- Datenübertragung über das Netzwerk (frontend ↔ backend).
- Import/Export von Informationen (zum Beispiel du willst einen Export deiner Bücher als JSON bauen!).
Im Vorstellungsgespräch: „Wie würdest du eine Liste von Bestellungen serialisieren und speichern?“ — super, wenn du nicht nur über einzelne Objekte sprichst, sondern auch die Serialisierung von Kollektionen erwähnst!
2. Wie Kollektionen bei der Serialisierung funktionieren
JSON und Kollektionen: eine kurze Lovestory
Wenn du ein normales Objekt serialisierst, wird es zu einem JSON-Objekt wie { "field": value }. Serialisierst du hingegen eine Liste oder ein Array, bekommst du ein JSON-Array [ ... ].
Visuell:
| C# | JSON |
|---|---|
|
|
|
|
|
|
Die Hauptmagie: Rufst du JsonSerializer.Serialize() für eine Kollektion auf — verwandelt sie der Serializer automatisch in ein Array! Umgekehrt funktioniert Deserialize<List<T>>() — und die Magie kehrt zurück.
Entsprechungen zwischen C#-Kollektionen und JSON-Arrays
| Kollektionstyp in C# | Beispiel | JSON |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3. Beispiel: Serialisierung und Deserialisierung eines Book-Arrays
Fangen wir mit einem minimalen Beispiel an. Nehmen wir unsere Klasse Book, die wir in früheren Vorlesungen verwendet haben:
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
}
Jetzt erstellen wir ein Array von Büchern, serialisieren es, speichern es in eine Datei und laden es wieder.
using System;
using System.IO;
using System.Text.Json;
namespace LibraryApp
{
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
}
class Program
{
static void Main()
{
// Erstellen wir ein Array von Büchern
Book[] books = new Book[]
{
new Book { Title = "Tri tovarishcha", Author = "Erich Maria Remarque" },
new Book { Title = "Master i Margarita", Author = "Mikhail Bulgakov" },
new Book { Title = "1984", Author = "Dzhordzh Oruell" }
};
// Serialisierung des Book-Arrays in einen String
var options = new JsonSerializerOptions { WriteIndented = true };
string json = JsonSerializer.Serialize(books, options);
Console.WriteLine("JSON des Book-Arrays:\n" + json);
// Schreiben in eine Datei (synchron)
File.WriteAllText("books.json", json);
// Lesen aus der Datei (synchron)
string jsonFromFile = File.ReadAllText("books.json");
// Deserialisierung zurück in ein Array
Book[]? booksFromFile = JsonSerializer.Deserialize<Book[]>(jsonFromFile);
// Ausgabe ins Console
Console.WriteLine("\nDeserialisierte Bücher:");
if (booksFromFile != null)
{
foreach (var book in booksFromFile)
{
Console.WriteLine($"- {book.Title} (Autor: {book.Author})");
}
}
}
}
}
Was passiert hier?
- Wir erstellen ein Book[]-Array und füllen es mit drei Büchern.
- Mit JsonSerializer.Serialize verwandeln wir das Array in einen hübsch formatierten JSON-String (Option WriteIndented macht die Ausgabe lesbar).
- Wir schreiben den String in eine Datei, lesen ihn zurück und deserialisieren — und haben wieder ein Array von Büchern!
- Wir prüfen, dass alle Daten korrekt wiederhergestellt wurden.
Prüfe, dass die Datei "books.json" im Programmordner erscheint. Öffne sie, dort steht ungefähr dieses JSON:
[
{
"Title": "Tri tovarishcha",
"Author": "Erich Maria Remarque"
},
{
"Title": "Master i Margarita",
"Author": "Mikhail Bulgakov"
},
{
"Title": "1984",
"Author": "Dzhordzh Oruell"
}
]
4. Beispiel: Serialisierung einer List<T>-Kollektion
Die Arbeit mit List<Book> unterscheidet sich nicht. Der Serializer erkennt die Kollektion und verwandelt sie in ein JSON-Array.
List<Book> myBooks = new List<Book>
{
new Book { Title = "Prestuplenie i nakazanie", Author = "Fedor Dostoevskiy" },
new Book { Title = "Voyna i mir", Author = "Lev Tolstoy" }
};
string jsonList = JsonSerializer.Serialize(myBooks, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(jsonList);
// Und so deserialisieren wir:
List<Book>? loadedBooks = JsonSerializer.Deserialize<List<Book>>(jsonList);
// Prüfen, dass alles zurückgekommen ist!
foreach (var book in loadedBooks!)
{
Console.WriteLine($"{book.Title} ({book.Author})");
}
Kann man auch einfach eine Liste von ints serialisieren?
Natürlich! Serialisierung funktioniert nicht nur für eigene Klassen, sondern auch für primitive Typen:
List<int> numbers = new List<int> { 10, 20, 30, 40 };
string jsonNums = JsonSerializer.Serialize(numbers); // Ergebnis: [10,20,30,40]
List<int>? loadedNums = JsonSerializer.Deserialize<List<int>>(jsonNums);
// loadedNums: List<int> mit den gleichen Werten
5. Schema und Analogien: wie der Serializer Kollektionen sieht
Um besser zu verstehen, wie die Serialisierung von Kollektionen funktioniert, betrachten wir ein einfaches Schema:
graph TD;
A[List[Book] in C#] -->|Serialize| B[JSON-Array als String]
B -->|Write| C[Datei books.json]
C -->|Read| D[JSON-String aus Datei]
D -->|Deserialize| E[List[Book] in C#]
Kurz beschrieben:
- Eine Kollektion oder ein Array wird als Array in JSON serialisiert ([ ... ]).
- Die Reihenfolge der Elemente bleibt erhalten (sofern du keine speziellen Einstellungen vornimmst).
- Jedes Element der Kollektion wird als eigenes Objekt serialisiert.
6. Besonderheiten bei der Serialisierung von Kollektionen: worauf achten
1. null und leere Kollektionen
Wenn eine Kollektion null ist, schreibt der Serializer standardmäßig einfach null in das JSON. Sei vorsichtig: in deiner Business-Logik sind eine leere Kollektion und null nicht unbedingt das Gleiche!
Ist die Kollektion leer (new List<Book>()), sieht das JSON wie [] aus — ein leeres Array. Das ist praktisch, wenn du explizit das Fehlen von Elementen zeigen willst.
2. Deserialisierung — Reihenfolge ist wichtig
Die Reihenfolge der Elemente im Array bleibt immer erhalten. Wenn du also drei Bücher in einer bestimmten Reihenfolge serialisiert hast, wird diese Reihenfolge beim Deserialisieren wiederhergestellt.
3. Kollektion mit verschiedenen Objekt-Typen?
System.Text.Json unterstützt Polymorphie nicht „out of the box“. Wenn du zum Beispiel eine List<Animal> mit Hunden und Katzen (jeweils abgeleitete Klassen) hast, kannst du standardmäßig nicht automatisch rekonstruieren, welcher konkrete Typ es war. Zur polymorphen Serialisierung gibt es zusätzliche Techniken, die wir später besprechen werden; bei gewöhnlichen Listen ist es aber einfach.
7. Typische Fehler und Missverständnisse
Fehler Nr.1: Wir serialisieren eine Kollektion, vergessen aber, dass sie Objekte mit privaten Feldern enthalten kann
JsonSerializer serialisiert nur öffentliche Eigenschaften (und nur solche mit Gettern/Settern). Wenn deine Klasse zum Beispiel so aussieht:
public class User
{
public string Login { get; set; }
private string Password { get; set; } // Wird nicht serialisiert!
}
Das Passwort landet nicht im JSON — gut aus Sicht der Sicherheit. Wenn du es trotzdem speichern willst, musst du die Eigenschaft öffentlich machen.
Fehler Nr.2: Serialisierung von Kollektionen mit null-Elementen
Wenn eine Kollektion null-Elemente enthält, z. B.: new List<Book> { null, book2 }, dann steht an der Stelle des ersten Elements null im JSON. Beim Deserialisieren gilt das gleiche! Beispiel-JSON:
[null, { "Title": "Voyna i mir", "Author": "Lev Tolstoy" }]
In der Praxis kommt das selten vor, aber wenn du Kollektionen mit „Lücken“ serialisierst — berücksichtige das in deiner Logik.
Fehler Nr.3: Falscher Typ beim Deserialisieren
Häufige Vertipper: du serialisierst eine Liste, versuchst aber, sie als Array zu deserialisieren (oder umgekehrt). Das funktioniert, wenn die Typen kompatibel sind (Book[] ↔ List<Book>), aber es kann Probleme geben, z. B. wenn du ein Array von Strings in ein Objekt statt in eine Kollektion deserialisieren willst.
GO TO FULL VERSION