JavaRush /Курсы /C# SELF /Сериализация простых коллекций:

Сериализация простых коллекций: List<T>, T[]

C# SELF
46 уровень , 0 лекция
Открыта

1. Введение

Мы с вами уже успели поработать с коллекциями. Без них никуда ни в программировании, ни в жизни. Представьте, что вы составляете список дел на день: купить продукты, позвонить врачу, забрать заказ. Вряд ли вы будете заводить для каждого дела отдельный блокнот. Куда проще и логичнее записать все задачи в один список.

То же самое и в программировании: когда объектов становится много — пользователей, заказов, сообщений — мы не всегда создаём под каждый отдельную переменную. Вместо этого используем коллекции: списки, словари, множества. Это позволяет удобно хранить, перебирать и обрабатывать сразу целые группы данных.

Сценарии из реальной жизни:

  • Хранение и обмен данными между приложениями: ваша коллекция книг может мигрировать из одной программы в другую.
  • Кеширование наборов данных на диск.
  • Передача данных по сети (frontend ↔ backend).
  • Импорт/экспорт информации (например, вы решили сделать свой экспорт книг в JSON!).

На собеседовании: «А как бы вы сериализовали и сохранили список заказов?» — будет классно, если вы назовёте не только один объект, но и сериализацию коллекций!

2. Как работают коллекции при сериализации

JSON и коллекции: недолгая история любви

Когда вы сериализуете обычный объект, он превращается в JSON-объект вида { "field": value }. А вот если сериализовать список или массив, получится JSON-массив [ ... ].

Визуально:

C# JSON
List<int> { 1, 2, 3 }
[1, 2, 3]
Book[]
[{"Title":"A","Author":"B"}, ...]
List<Book>
[{"Title":"A"}, {"Title":"B"}]

Главная магия: Вызываем JsonSerializer.Serialize() для коллекции — и он автоматом превращает её в массив! В обратную сторону Deserialize<List<T>>() — и волшебство срабатывает снова.

Соответствие между коллекциями C# и JSON-массивами

Тип коллекции в C# Пример JSON
Book[]
new Book[] { ... }
[ { ... }, { ... } ]
List<Book>
new List<Book> { ... }
[ { ... }, { ... } ]
int[]
new int[] { 1, 2, 3 }
[1, 2, 3]
List<string>
new List<string> { "a", "b" }
["a", "b"]
List<List<Book>>
new List<List<Book>> { ... }
[ [ { ... } ], [ { ... } ] ]

3. Пример: сериализация и десериализация массива книг

Давайте начнём с минимального примера. Возьмём наш класс Book, который мы уже писали в прошлых лекциях:

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

Теперь создадим массив книг, сериализуем его, сохраним в файл и загрузим обратно.

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()
        {
            // Создадим массив книг
            Book[] books = new Book[]
            {
                new Book { Title = "Три товарища", Author = "Эрих Мария Ремарк" },
                new Book { Title = "Мастер и Маргарита", Author = "Михаил Булгаков" },
                new Book { Title = "1984", Author = "Джордж Оруэлл" }
            };

            // Сериализация массива книг в строку
            var options = new JsonSerializerOptions { WriteIndented = true };	
            string json = JsonSerializer.Serialize(books, options);
            Console.WriteLine("JSON массива книг:\n" + json);

            // Запись в файл (синхронно)
            File.WriteAllText("books.json", json);

            // Чтение из файла (синхронно)
            string jsonFromFile = File.ReadAllText("books.json");

            // Десериализация обратно в массив
            Book[]? booksFromFile = JsonSerializer.Deserialize<Book[]>(jsonFromFile);

            // Выводим результат на консоль
            Console.WriteLine("\nДесериализованные книги:");
            if (booksFromFile != null)
            {
                foreach (var book in booksFromFile)
                {
                    Console.WriteLine($"- {book.Title} (автор: {book.Author})");
                }
            }
        }
    }
}

Что здесь происходит?

  • Мы создаём массив Book[], заполняем его тремя книгами.
  • Через JsonSerializer.Serialize превращаем массив в красивую JSON-строку (опция WriteIndented делает форматирование читаемым).
  • Записываем её в файл, читаем обратно и десериализуем — и вот, у нас снова есть массив книг!
  • Проверяем, что все данные корректно восстановились.

Проверьте, что файл "books.json" появляется в папке с программой. Откройте его, там будет примерно такой JSON:

[
  {
    "Title": "Три товарища",
    "Author": "Эрих Мария Ремарк"
  },
  {
    "Title": "Мастер и Маргарита",
    "Author": "Михаил Булгаков"
  },
  {
    "Title": "1984",
    "Author": "Джордж Оруэлл"
  }
]

4. Пример: сериализация коллекции List<T>

Работа с List<Book> ничем не отличается. Сериализатор видит коллекцию и превращает её в JSON-массив.

List<Book> myBooks = new List<Book>
{
    new Book { Title = "Преступление и наказание", Author = "Фёдор Достоевский" },
    new Book { Title = "Война и мир", Author = "Лев Толстой" }
};

string jsonList = JsonSerializer.Serialize(myBooks, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(jsonList);

// А десериализуем вот так:
List<Book>? loadedBooks = JsonSerializer.Deserialize<List<Book>>(jsonList);

// Проверяем, что всё вернулось!
foreach (var book in loadedBooks!)
{
    Console.WriteLine($"{book.Title} ({book.Author})");
}

А можно ли сериализовать просто список целых чисел?

Конечно! Сериализация работает не только для ваших классов, но и для простых типов:

List<int> numbers = new List<int> { 10, 20, 30, 40 };
string jsonNums = JsonSerializer.Serialize(numbers); // результат: [10,20,30,40]
List<int>? loadedNums = JsonSerializer.Deserialize<List<int>>(jsonNums);
// loadedNums: List<int> c теми же значениями

5. Схема и аналогии: как сериализатор видит коллекции?

Чтобы лучше понять, как работает сериализация коллекций, взглянем на простую схему:

graph TD;
    A[List[Book] в C#] -->|Serialize| B[JSON-массив в строке]
    B -->|Write| C[Файл books.json]
    C -->|Read| D[Строка JSON из файла]
    D -->|Deserialize| E[List[Book] в C#]

Коротко описывая процесс:

  • Коллекция или массив сериализуется как массив в JSON ([ ... ]).
  • Порядок элементов сохраняется (если вы не вмешались специальными настройками).
  • Каждый элемент коллекции сериализуется как свой объект.

6. Особенности сериализации коллекций: на что обратить внимание

1. null и пустые коллекции

Если коллекция null, сериализатор по умолчанию просто запишет null в JSON. Будьте аккуратны, если в вашей бизнес-логике пустая коллекция и null — не одно и то же!

Если коллекция пустая (new List<Book>()), JSON будет выглядеть как [] — пустой массив. Это удобно, когда надо явно показать отсутствие элементов.

2. Десериализация — порядок важен

Порядок элементов в массиве всегда сохраняется. То есть если сериализовали три книги в таком же порядке, такой же порядок и восстановится.

3. Коллекция с объектами разных типов?

System.Text.Json не поддерживает полиморфизм «из коробки». То есть если у вас, например, List<Animal> с собаками и котами (где каждый — производный класс), то восстановить «какой именно это тип» по умолчанию нельзя. До полиморфной сериализации мы ещё дойдём, но на обычных списках — всё просто.

7. Типичные ошибки и распространённые недоразумения

Ошибка №1: Сериализуем коллекцию, но забываем, что в ней могут быть объекты с приватными полями

JsonSerializer сериализует только публичные свойства (и только с геттерами/сеттерами). Если у вас класс вот такой:

public class User
{
    public string Login { get; set; }

    private string Password { get; set; }  // Не будет сериализовано!
}

Пароль в JSON не попадёт, и это хорошо для безопасности. Но если вы хотели его сохранить — не забудьте сделать свойство публичным.

Ошибка №2: Сериализация коллекций с null-элементами

Если коллекция содержит null, например: new List<Book> { null, book2 }, то после сериализации на месте первого элемента будет null. При десериализации — точно так же! Пример такого JSON:

[null, { "Title": "Война и мир", "Author": "Лев Толстой" }]

На практике это бывает редко, но если вы сериализуете коллекцию, где могут быть "дырки" — учитывайте это в логике.

Ошибка №3: Не тот тип при десериализации

Частая опечатка: сериализовали список, а десериализуем в массив (или наоборот). Это работает, если типы совместимы (Book[]List<Book>), но иногда могут быть нюансы, если, например, вы захотели десериализовать массив строк в объект, а не в коллекцию.

2
Задача
C# SELF, 46 уровень, 0 лекция
Недоступна
Сериализация и десериализация списка строк
Сериализация и десериализация списка строк
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ