C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
68: JSON Serialization with System.Text.Json
Most of the time, when we're talking about JSON in C#, we're just trying to get an object out of our memory and into a string so we can send it over a network or save it to a file. For years, everyone used Newtonsoft.Json, but System.Text.Json is now the built-in standard. It's faster and more memory-efficient, though it's a bit more strict. Let's see how it actually behaves.
Let's see what happens by default
I've got a simple GameCharacter class here. I want to take this character and turn it into a JSON string. I'll start with the most basic approach possible: JsonSerializer.Serialize.
using System.Text.Json;
public class GameCharacter
{
public string Name { get; set; }
public int Level { get; set; }
public List<string> Inventory { get; set; }
}
var hero = new GameCharacter
{
Name = "Valerius",
Level = 12,
Inventory = new List<string> { "Iron Sword", "Health Potion", "Old Map" }
};
string jsonString = JsonSerializer.Serialize(hero);
Console.WriteLine(jsonString);
// Output: {"Name":"Valerius","Level":12,"Inventory":["Iron Sword","Health Potion","Old Map"]}
It worked, but look at that output. It's a single, cramped line, and the property names start with capital letters. While this is valid JSON, most web APIs expect camelCase (lowercase first letter), and if I'm debugging this in a text editor, I'd much rather it be formatted nicely.
Wait, this looks like C#, not JSON
To fix the casing and the readability, I can't just pass the object into the serializer. I need to pass an instance of JsonSerializerOptions. This is where the actual configuration happens.
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
string prettyJson = JsonSerializer.Serialize(hero, options);
Console.WriteLine(prettyJson);
/*
Output:
{
"name": "Valerius",
"level": 12,
"inventory": [
"Iron Sword",
"Health Potion",
"Old Map"
]
}
*/
That's much better. By setting PropertyNamingPolicy to CamelCase, the serializer automatically maps our C# Name property to "name" in the JSON string. WriteIndented just adds the whitespace and line breaks. It's a small change, but it makes a huge difference when you're staring at a log file for three hours.
Hiding the messy bits
Now, here is a real-world problem. Let's say my GameCharacter class has an InternalDbId. This is a GUID we use for database lookups, but we absolutely do not want to send that to the client or save it in a public-facing save file. It's internal noise.
public class GameCharacter
{
[JsonIgnore]
public Guid InternalDbId { get; set; }
public string Name { get; set; }
public int Level { get; set; }
}
I just added the [JsonIgnore] attribute. When I run the serialization again, InternalDbId simply vanishes from the output. It's the cleanest way to handle "private" data that still needs to be a public property for other parts of your C# code to work.
Bringing the data back to life
Serialization is great, but it's useless if we can't get the object back. This is where JsonSerializer.Deserialize<T> comes in. Let's take a JSON string—maybe one we read from a file—and turn it back into a GameCharacter object.
string rawJson = "{\"name\":\"Valerius\",\"level\":12}";
// IMPORTANT: We must use the same options we used to serialize!
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
GameCharacter restoredHero = JsonSerializer.Deserialize<GameCharacter>(rawJson, options);
Console.WriteLine($"Welcome back, {restoredHero.Name}!");
One thing to watch out for: if you forget the JsonSerializerOptions during deserialization, C# will look for a property named "name" (lowercase) in your class. Since your class has Name (uppercase), it won't find a match and will just leave the property as null or 0. It won't throw an error; it'll just fail silently. That's a classic bug that's a pain to track down, so always keep your options consistent.
📋 Practical Task
Exercise: Building a Save-Game System for a Space RPG
You are tasked with creating a save/load system for a Space RPG. You need to implement a system that saves a ShipState object to a JSON string and then loads it back.
Requirements:
- Create a
ShipStateclass with the following properties:ShipName(string)FuelLevel(double)CrewMembers(List of strings)SecretEncryptionKey(string) — This should not be included in the JSON output.
- Write a method
SaveShip(ShipState ship)that returns a JSON string. The JSON must be indented and use camelCase naming. - Write a method
LoadShip(string json)that takes a JSON string and returns aShipStateobject. - In your
Mainmethod, create a ship, save it to a string, print that string to the console to verify the formatting and the missing secret key, and then deserialize it back into a new object to verify the data persisted.
There are no comments for now.