1. Introduction
Reminder: Serialization is a way to save an object's state as a string, file, or stream so you can later restore that object (deserialize) — and you get the object back with the same data.
A typical real-life scenario:
1) You have an object, for example, a user with a name and an age.
2) You need to save it — send over the network, write to a file, or, say, into JSON format.
3) Later you take the data from the string/file back — and you get the object again!
In C# this is done in just a couple of lines. Let's see how exactly.
Our application
We're building a small "Contacts Manager" app. Suppose we have a class Person that we want to serialize.
public class Person
{
// Public properties are required for serialization!
public string Name { get; set; }
public int Age { get; set; }
// Parameterless constructor is required for XmlSerializer
public Person() { }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
If you're not familiar with this syntax, don't worry — later in the course we'll cover classes and properties in detail. For now treat this as a data model for experiments. Note: public properties Name and Age are important for serialization, and XmlSerializer needs a public parameterless constructor.
2. JSON serialization with System.Text.Json
Simple example
We promised — here's how JSON serialization looks:
using System;
using System.Text.Json;
Person person = new Person("Alice", 28);
// Serialization: turn the object into a JSON string
string json = JsonSerializer.Serialize(person);
Console.WriteLine("JSON:");
Console.WriteLine(json);
What will show on the screen?
JSON:
{"Name":"Alice","Age":28}
It's simple: object → JSON. That's the magic!
Deserialization — getting it back
Now let's do the reverse — restore an object from a JSON string:
string json = "{\"Name\":\"Bob\",\"Age\":35}";
// Deserialization: restore an object of type Person from the JSON string
Person restored = JsonSerializer.Deserialize<Person>(json);
Console.WriteLine("Restored object:");
Console.WriteLine($"Name: {restored.Name}, age: {restored.Age}");
Result:
Restored object:
Name: Bob, age: 35
Note: if the data structure doesn't match (for example, a property is missing), the corresponding field will remain at its default value (null for reference types, 0 for numbers, etc.).
3. XML serialization/deserialization with XmlSerializer
XML serialization — first look
using System;
using System.IO;
using System.Xml.Serialization;
Person person = new Person("Kate", 22);
// Create a serializer for type Person
var serializer = new XmlSerializer(typeof(Person));
// Write XML to a file
using (var stream = new FileStream("person.xml", FileMode.Create))
{
serializer.Serialize(stream, person);
// The stream will be closed automatically at the end of the using block
}
Console.WriteLine("XML file created!");
The file person.xml will contain something like this:
<?xml version="1.0"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Kate</Name>
<Age>22</Age>
</Person>
Important point:
For serializing to a file you use a stream (Stream, e.g. FileStream). If you want to serialize to a string (for sending over the network), use StringWriter:
var serializer = new XmlSerializer(typeof(Person));
using (var sw = new StringWriter())
{
serializer.Serialize(sw, person);
string xmlString = sw.ToString();
Console.WriteLine(xmlString);
}
Deserialization from XML
using (var stream = new FileStream("person.xml", FileMode.Open))
{
// Don't forget to cast to the needed type!
Person restored = (Person)serializer.Deserialize(stream);
Console.WriteLine($"Name: {restored.Name}, age: {restored.Age}");
}
Again: XmlSerializer requires the serializable class to have a public default (parameterless) constructor.
4. Working with files vs strings: what to choose?
In real life serialization can go directly to a string (for sending over the network/storing in a DB) or to a file (for long-term storage).
Serialize to a string (for example, to send via an API):
- JSON: use JsonSerializer.Serialize(obj).
- XML: via StringWriter.
Serialize to a file (for example, for export/backup):
- JSON: save the string to a file with normal file write operations.
- XML: write directly to a stream using XmlSerializer.
Example: serialize to a file and back (JSON)
using System.IO;
using System.Text.Json;
Person person = new Person("Tom", 42);
// Serialize to a string
string json = JsonSerializer.Serialize(person);
// Write to a file
File.WriteAllText("contact.json", json);
// Read from the file
string readJson = File.ReadAllText("contact.json");
Person restored = JsonSerializer.Deserialize<Person>(readJson);
Console.WriteLine($"{restored.Name}, age: {restored.Age}");
5. JSON vs XML comparison
Process visualization
To avoid confusion, here's the serialization/deserialization flow diagram:
flowchart LR
A[Object] -- serialize --> B[String/File/Stream]
B -- deserialize --> C[Object]
A -. JSON or XML .-> B
B -. JSON or XML .-> C
You can think of serialization as "packing a suitcase", and deserialization as "unpacking it at home."
Comparison table
| Functionality | JSON (System.Text.Json) | XML (XmlSerializer) |
|---|---|---|
| Read/write to string | ++ | + |
| Read/write to file | ++ | ++ |
| Requires parameterless constructor | No | Yes |
| Human readability | ++ | + |
| Strict data schema (validation) | - | ++ |
| Flexibility (customization attributes) | + | ++ |
| Performance | ++ | + |
| Internet compatibility | ++ | + |
++ — very good, + — ok, - — not supported
6. How to add serialization to our app
Let's say the "Contacts Manager" needs the ability to save a list of user contacts to a file and restore it.
Context: we have a list of contacts (List<Person>).
List<Person> contacts = new List<Person>
{
new Person("Bill", 30),
new Person("Pete", 25),
new Person("Mary", 27)
};
// Save all contacts — serialize to JSON
string jsonContacts = JsonSerializer.Serialize(contacts);
File.WriteAllText("contacts.json", jsonContacts);
// Restore the contacts list
string readContactsJson = File.ReadAllText("contacts.json");
List<Person> restored = JsonSerializer.Deserialize<List<Person>>(readContactsJson);
foreach (var c in restored)
{
Console.WriteLine($"{c.Name}, age: {c.Age}");
}
You can do the same with XML, but there are specifics. When serializing collections with XmlSerializer it's common to wrap the list in a separate container class (root element) — it's easier to control element names and format that way.
7. Common mistakes in serialization and deserialization
Mistake #1: type mismatch during serialization and deserialization.
You serialized a List<Person> — you must deserialize into List<Person> as well, not into List<object> or IEnumerable<Person>. Otherwise you'll get an error or unexpected results.
Mistake #2: trying to serialize non-public fields and properties.
Typical serializers (JsonSerializer, XmlSerializer) work with public members. If a property lacks a public getter/setter, its value may not get into JSON/XML, and you'll wonder why it's null.
Mistake #3: missing parameterless constructor.
For XmlSerializer a public default constructor is mandatory. If it's missing — you'll get an exception during deserialization.
Mistake #4: misunderstanding object references.
If one object contains a reference to another, serialization goes "by value" (as an embedded object). References themselves are not preserved, which can lead to duplicated data or problems with cyclic references.
Mistake #5: trying to mix serialization formats.
XML and JSON are different formats with different serializers. You can't pass a JSON string to XmlSerializer and vice versa — you'll get an error.
GO TO FULL VERSION