1. Przypominamy JSON
JSON oznacza JavaScript Object Notation. Pomimo „JavaScript” w nazwie, ten format jest całkowicie neutralny językowo i przyjazny dla wszystkich (no prawie wszystkich) języków programowania, w tym C#. Został wymyślony po to, żeby wygodnie i czytelnie opisywać dane — obiekty, tablice, listy i słowniki — w postaci zwykłego tekstu.
W dzisiejszym świecie, gdzie niemal każdy program komunikuje się z innymi programami, JSON stał się de facto standardem do serializacji i wymiany danych strukturalnych. Używa się go wszędzie: od REST API po przechowywanie ustawień użytkownika, a nawet do wewnętrznej komunikacji między mikroserwisami. I to nie bez powodu — jest czytelny dla człowieka (jeśli ten człowiek się nie boi klamerek), prosty do parsowania i wspierany przez wszystkie nowoczesne języki i biblioteki.
Dlaczego nie XML?
JSON jest prostszy, krótszy i łatwiejszy do czytania niż XML. Poza tym ma mniej zbędnego szumu i tagów, lepiej pasuje do struktur danych większości języków programowania. I nie trzeba się bawić w zamykające tagi, cudzysłowy i resztę XML-owej biurokracji. Krótko — JSON to szybciej, prościej, wygodniej.
2. Podstawowe elementy składni JSON
Wyobraźmy sobie, że JSON to proste drzewo (albo matrioszka), składające się z obiektów, tablic i danych elementarnych. Oto jakie „klocki” mamy do dyspozycji:
Obiekty (Objects)
Obiekt JSON to zbiór par „klucz: wartość”, otoczony klamrami { }.
Przykład:
{
"name": "Alice",
"age": 23
}
W C# taką strukturę można przedstawić jako klasę lub słownik.
Tablice (Arrays)
Tablica JSON to uporządkowana lista elementów (wartości dowolnego typu), zamknięta w nawiasach kwadratowych [ ].
Przykład:
[1, 2, 3, 42]
Albo tak:
[
{"name": "Ivan"},
{"name": "Olga"}
]
W C# — to List<T>, T[] i podobne kolekcje.
Pary „klucz-wartość”
Klucze to zawsze stringi (w podwójnych cudzysłowach!), a wartości mogą być dowolnych typów danych dozwolonych w JSON.
Przykład:
{
"id": 123,
"login": "student",
"isActive": true
}
Typy danych w JSON
| Typ JSON | Przykład | Opis |
|---|---|---|
| Liczba (Number) | |
Liczba całkowita lub zmiennoprzecinkowa |
| String (String) | |
Zawsze w podwójnych cudzysłowach |
| Boolean (Boolean) | |
Wartość logiczna |
| null | |
Brak wartości |
| Obiekt (Object) | |
Słownik lub encja z polami |
| Tablica (Array) | |
Sekwencja wartości |
Przykład — wszystko razem:
{
"id": 1,
"name": "Bob",
"scores": [10, 20, 30],
"profile": {
"email": "bob@mail.com",
"phone": null
},
"isAdmin": false
}
Widzisz, jak kompaktowo i logicznie da się opisać cały obiekt użytkownika.
3. Zasady zapisu JSON
Stringi zawsze w podwójnych cudzysłowach
Nawet jeśli bardzo chcesz użyć pojedynczych, JSON tego nie wybaczy. Tak — poprawnie:
{ "name": "Vera" }
Tak — błąd:
{ 'name': 'Vera' }
Klucze — tylko stringi
W przeciwieństwie do C#, gdzie klucz słownika może być choćby int albo enum, w JSON klucz to zawsze string:
{ "2025": "Rok C#", "favorite": true }
Żadnych końcowych przecinków
W przeciwieństwie do tablic i obiektów w C#, dodatkowy przecinek przed zamykającym nawiasem to błąd składniowy w JSON!
// BŁĄD! (ostatni przecinek jest niedozwolony)
{
"id": 10,
"name": "Oleg",
}
Poprawnie:
{
"id": 10,
"name": "Oleg"
}
Spacje i złamania linii
Można je dodawać dla czytelności, parsery je ignorują. Zwykle dla formatu „dla ludzi” używa się pretty-printed (sformatowanego) JSON-a, a do przesyłania po sieci — minified (w jednej linii, bez spacji).
4. Jak obiekty C# są przekształcane w JSON
Jeśli serializujesz obiekt za pomocą System.Text.Json.JsonSerializer.Serialize(), pola i właściwości obiektu zamieniają się w pary „klucz-wartość”.
Przykład klasy C# i serializacji
public class Book
{
public string Title { get; set; }
public int Pages { get; set; }
}
var book = new Book { Title = "CLR via C#", Pages = 900 };
string json = JsonSerializer.Serialize(book);
Console.WriteLine(json); // {"Title":"CLR via C#","Pages":900}
Kolekcje
- List<int> zamienia się w [1,2,3]
- string[] zamienia się w ["hi", "wow"]
- List<Person> — w tablicę obiektów
Słowniki
Słownik typu Dictionary<string, int> zamienia się w obiekt:
var dict = new Dictionary<string, int>
{
["apples"] = 5, ["bananas"] = 10
};
string json = JsonSerializer.Serialize(dict);
// {"apples":5,"bananas":10}
5. Schemat wizualny: jak budowany jest JSON
Zagnieżdżenie — jak matrioszka
Obiekt
│
├── Para: "name": "Alex"
├── Para: "hobbies": tablica
│ │
│ ├── "skiing"
│ └── "programming"
└── Para: "profile": obiekt
│
├── "age": 42
└── "city": "Basel"
W efekcie:
{
"name": "Alex",
"hobbies": ["skiing", "programming"],
"profile": {
"age": 42,
"city": "Basel"
}
}
6. Typowe błędy i niuanse składni
W programowaniu nie ma idealnego świata — nawet w JSON są pułapki! Jeśli spróbujesz wysłać JSON z nieprawidłowymi cudzysłowami, z dodatkowymi przecinkami lub z kluczami nieowiniętymi w cudzysłowy — parser zwróci błąd.
Jeszcze jedna „niespodzianka” — liczby z wiodącymi zerami. W JSON to zabronione (np. 0123 — błąd).
Warto wiedzieć: Niektóre parsery (np. JavaScript-owy JSON.parse) są bardziej łagodne i mogą „wybaczyć” drobne naruszenia. Ale większość „surowych” parserów (np. w C# i .NET) będzie marudzić przy najmniejszym naruszeniu składni.
7. Przykłady przekształcania danych C# do JSON
Spróbujmy zserializować bardziej złożoną strukturę w praktyce. Nasza edukacyjna aplikacja się rozwija: załóżmy, że mamy teraz listę studentów i chcemy zapisać ich do pliku JSON.
Zdefiniujmy klasę:
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
Wypełnimy listę:
var students = new List<Student>
{
new Student { Name = "Anna", Age = 20 },
new Student { Name = "Nikita", Age = 22 }
};
Serializacja:
using System.Text.Json;
// Serializujemy listę studentów do stringa JSON
string json = JsonSerializer.Serialize(students, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(json);
/*
[
{
"Name": "Anna",
"Age": 20
},
{
"Name": "Nikita",
"Age": 22
}
]
*/
Widzisz, jakie to wygodne? Każdy student to osobny obiekt wewnątrz JSON-owej tablicy.
8. Mini-generator: jak „ręcznie” napisać JSON
Czasem trzeba napisać JSON samemu, np. tworząc testowe dane ręcznie. Oto checklist:
- Zewnętrzne klamry — dla obiektu, zewnętrzne nawiasy kwadratowe — dla tablicy.
- Klucz zawsze — string w podwójnych cudzysłowach.
- Wartości — stringi (w podwójnych cudzysłowach), liczby, true, false, null, obiekt ({}), tablica ([]).
- Tylko przecinki między elementami, nie po ostatnim!
- Wcięcia i spacje dla czytelności (ale nieobowiązkowe).
GO TO FULL VERSION