CodeGym /Kurse /C# SELF /Abfolge der Schritte und Beispiele: Serialisierung von Ob...

Abfolge der Schritte und Beispiele: Serialisierung von Objekten

C# SELF
Level 43 , Lektion 1
Verfügbar

1. Einführung

Wir sind es schon gewohnt, Objekte in unseren Programmen zu erstellen. Erinnerst du dich, wir werden bald Klassen und Objekte tiefer behandeln, aber schon jetzt verstehen wir, dass Variablen, Listen, sogar einfache Strings — das nicht einfach nur Daten sind, sondern „Entities“ in unserem Programm. Zum Beispiel können wir eine Variable erstellen int age = 30; oder string name = "Vasya";. Aber was, wenn wir Informationen über einen ganzen Benutzer speichern müssen, der Name, Alter, Adresse, eine Liste der Lieblingsbücher und vieles mehr hat?

Stell dir vor: du schreibst ein Spiel. Du hast ein Objekt Player mit vielen Eigenschaften: Gesundheit, Level, Inventar (Liste von Items), Koordinaten auf der Karte usw. Der Spieler spielt, levelt auf, findet coole Artefakte. Und dann entscheidet er sich, das Spiel zu verlassen. Was passiert? Alle Daten über seine Abenteuer, die im Speicher waren, verschwinden! Traurig! Damit das nicht passiert, müssen wir den Zustand des Objekts Player in eine Datei speichern, und wenn der Spieler zurückkommt, ihn wieder laden.

Und hier kommt die Serialisierung ins Spiel. Sie baut die Brücke zwischen den „lebenden“ Objekten im Speicher und den „toten“, aber beständigen Daten auf der Festplatte.

2. Der Serialisierungsprozess (vom Objekt zur Datei)

Lass uns auseinandernehmen, wie diese „Magie“ funktioniert, ein Objekt in Bytes zu verwandeln, die man in eine Datei schreiben kann.

Stell dir vor, wir haben diese Klasse Book (Buch):


// Das ist unser "Blueprint" oder "Plan" zur Erstellung von Book-Objekten
public class Book
{
    // Eigenschaften des Buches
    public string Title { get; set; } // Titel des Buches
    public string Author { get; set; } // Autor
    public int Year { get; set; } // Erscheinungsjahr

    // Konstruktor - spezielle Methode zum Erstellen neuer Book-Objekte
    public Book(string title, string author, int year)
    {
        Title = title;
        Author = author;
        Year = year;
    }

    // Methode zur bequemen Ausgabe von Informationen über das Buch (für die Serialisierung nicht zwingend erforderlich, aber nützlich)
    public void DisplayInfo()
    {
        Console.WriteLine($"Titel: {Title}, Autor: {Author}, Jahr: {Year}");
    }
}

Schritt 1: Erstellen des zu serialisierenden Objekts.

Zuerst brauchen wir natürlich ein Objekt, das wir speichern wollen. Zum Beispiel erstellen wir eine Instanz von Book:

Book myFavoriteBook = new Book("Autostopp durch die Galaxie", "Douglas Adams", 1979);

Dieses Objekt myFavoriteBook befindet sich jetzt im Arbeitsspeicher.

Schritt 2: Auswahl des Werkzeugs (Serializer).

Wir können das Objekt nicht einfach so auf die Festplatte „kopieren“. Der Computer versteht Objekte in Dateien nicht direkt — er braucht Bytes. Wir brauchen ein spezielles Werkzeug — einen Serializer. Seine Aufgabe ist es, unser Objekt in seine Bestandteile zu zerlegen (seine Eigenschaften: Title, Author, Year) und diese Teile in eine Bytefolge oder eine Textzeichenfolge (z.B. JSON oder XML) zu verwandeln.

Heute gehen wir nicht in konkrete Implementierungen — denk einfach an ihn als eine spezielle „Transformationsbox“.

Schritt 3: Umwandlung des Objekts in einen Datenstrom.

Der Serializer nimmt unser Objekt myFavoriteBook, schaut sich seine Eigenschaften (Title, Author, Year) an und wandelt jede einzelne in ein Format um, das geschrieben werden kann. All diese Bytes (oder Textzeichen) werden zu einem einzigen Datenstrom zusammengeführt — einem langen „Band“ von Informationen.

Schritt 4: Schreiben des Stroms in eine Datei.

Jetzt, wo wir dieses „Band von Bytes“ haben, verwenden wir unsere alten Bekannten FileStream und vielleicht StreamWriter (wenn ein Textformat wie JSON gewählt wurde) oder einfach FileStream (für reine Binärdaten), um diesen Strom auf die Festplatte zu schreiben.

3. Der Deserialisierungsprozess (von der Datei zum Objekt)

Schritt 1: Lesen des Datenstroms aus der Datei.

Wir benutzen wieder FileStream und falls nötig StreamReader (bei Textformaten), um den Inhalt der Datei zu lesen. Die Daten kommen als „Band“ von Bytes oder Text.

Schritt 2: Auswahl des Werkzeugs (Deserializer).

Wir brauchen das Gegenstück — einen Deserializer. Er muss wissen, wie man die empfangenen Bytes/Text interpretiert und die Struktur des Objekts korrekt wiederherstellt. Sehr wichtig: Für Deserialisierung verwendet man normalerweise denselben Serializer-Typ (und üblicherweise dieselbe Bibliothek), sonst versteht dein „Assembler“ die Anweisungen nicht.

Schritt 3: Umwandlung des Stroms zurück in ein Objekt.

Der Deserializer liest die Daten, erkennt, wo Title ist, dann Author, dann Year, und basierend darauf erstellt er ein neues Book-Objekt im Speicher und füllt dessen Eigenschaften.

Schritt 4: Fertiges Objekt erhalten.

Voilá! Wir haben wieder ein vollständiges Book-Objekt im Arbeitsspeicher, mit dem wir weiterarbeiten können.

Beispiel: Wir speichern unser „Super-Buch“ manuell (zum Verständnis der Idee)

Wir verzichten vorerst auf spezielle Bibliotheken: wir machen eine einfache „manuelle“ Serialisierung und Deserialisierung mit StreamWriter und StreamReader. Das hilft, das Prinzip zu verstehen.

Unser Objekt Book:

public class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
    public int Year { get; set; }

    public Book(string title, string author, int year)
    {
        Title = title;
        Author = author;
        Year = year;
    }

    public void DisplayInfo()
    {
        Console.WriteLine($"Titel: \"{Title}\", Autor: {Author}, Jahr: {Year}");
    }
}

Manuelle Serialisierung: Methode SaveBookToTextFile

Erstellen wir eine Methode, die die Eigenschaften des Buches in eine Textdatei speichert, jeweils eine Eigenschaft pro Zeile.

void SaveBookToTextFile(Book book, string filePath)
{
    using var writer = new StreamWriter(filePath);
    writer.WriteLine(book.Title);
    writer.WriteLine(book.Author);
    writer.WriteLine(book.Year);
}

Was passiert hier? Wir öffnen einen StreamWriter und schreiben nacheinander Title, Author, Year — das ist unser einfachstes Serialisierungsschema.

Wenn du den Code ausführst, würde der Inhalt der Datei so aussehen:


Autostopp durch die Galaxie
Douglas Adams
1979

Manuelle Deserialisierung: Methode LoadBookFromTextFile

Schreiben wir eine Methode, die die Daten liest und ein neues Book-Objekt zusammensetzt.

Book LoadBookFromTextFile(string filePath)
{
    using var reader = new StreamReader(filePath);
    string title = reader.ReadLine();
    string author = reader.ReadLine();
    int year = int.Parse(reader.ReadLine());
    return new Book(title, author, year);
}

Und verwenden wir diese Methoden in Main:

//wir erstellen ein Objekt
var myBook = new Book("Autostopp durch die Galaxie", "Douglas Adams", 1979);
string filePath = "my_favorite_book.txt";

//wir speichern es in einer Datei
SaveBookToTextFile(myBook, filePath);

//wir lesen aus der Datei
Book loadedBook = LoadBookFromTextFile(filePath);

Was passiert in LoadBookFromTextFile? Wir öffnen einen StreamReader und lesen in derselben Reihenfolge die Zeilen: zuerst den Titel, dann den Autor, dann das Jahr und wandeln es mit int.Parse um. Danach erstellen wir eine neue Instanz von Book.

In der Praxis sollte man Checks hinzufügen (File.Exists) und Fehlerbehandlung mit try-catch, aber hier konzentrieren wir uns auf das Grundprinzip.

Warum „manuelle“ Serialisierung schlecht ist (und warum Bibliotheken nötig sind)

  • Viel manueller Code. Jede Eigenschaft muss geschrieben und dann gelesen werden. Wenn es viele Objekte und Felder gibt, wächst der Code schnell.
  • Brüchig gegenüber Änderungen. Hast du eine neue Eigenschaft Pages (int) hinzugefügt? Dann musst du sowohl Schreiben als auch Lesen anpassen und strikt die Reihenfolge beachten.
  • Komplexe Strukturen. Geschachtelte Collections und Objekte (z.B. List<Chapter>) verwandeln den Code in „Spaghetti“.
  • Formate und Effizienz. Textformate sind simpel, aber nicht immer kompakt oder sicher; für Binärdaten muss man manuell mit Bytes, BinaryWriter/BinaryReader usw. arbeiten.
  • Keine Metadaten. Unsere Datei „weiß“ nicht, dass die erste Zeile Title ist und die dritte Year. Spezialisierte Serializer können Metadaten speichern und sind robuster gegenüber Modelländerungen.

Deshalb verwendet man in echten Projekten fertige Serializer-Bibliotheken, die automatisch Objekte zerlegen/zusammenbauen können, mit JSON, XML und Binärformaten arbeiten und Änderungen in Modellen besser tolerieren. Mehr dazu in der nächsten Vorlesung!

Praktische Anwendung: Wozu braucht man Serialisierung?

  • Speichern und Laden von Daten. Einstellungen, Spielstände, Konfigurationen.
  • Datenübertragung über das Netzwerk. Austausch komplexer Objekte zwischen Services (oft in JSON).
  • Caching. Schnelle Wiederverwendung zuvor erhaltener Daten.
  • Logging komplexer Objekte. Nützlich für Debugging und Audit.
  • Tiefes Kopieren von Objekten. Serialisierung + Deserialisierung als Möglichkeit, ein Objektgraph zu klonen.

Serialisierung ist einer der Grundpfeiler moderner Software: vom Speichern des Spielfortschritts bis zur Arbeit mit Webservices — sie ist überall!

Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION