Отражение и создание источника в System.Text.Json

В этой статье описываются различия между отражением и исходным поколением, так как они связаны с System.Text.Json сериализацией. Он также содержит рекомендации по выбору оптимального подхода к вашему сценарию.

Коллекция метаданных

Для сериализации или десериализации типа требуется информация о том, JsonSerializer как получить доступ к членам типа. JsonSerializer требуется следующая информация:

  • Как получить доступ к свойствам getters и полям для сериализации.
  • Как получить доступ к конструктору, наборам свойств и полям десериализации.
  • Сведения о том, какие атрибуты использовались для настройки сериализации или десериализации.
  • Конфигурация среды выполнения из JsonSerializerOptions.

Эта информация называется метаданными.

Отражение

По умолчанию JsonSerializer собирает метаданные во время выполнения с помощью рефлексии. Впервые, когда JsonSerializer сериализует и десериализует тип, он собирает и кэширует эти метаданные. Процесс сбора метаданных занимает время и использует память.

Создание источника

В качестве альтернативы System.Text.Json можно использовать функцию генерации кода C#, чтобы повысить производительность, уменьшить использование памяти и упростить оптимизацию сборок, что сокращает размер приложения. Кроме того, некоторые API отражения нельзя использовать в нативных приложениях AOT, поэтому для этих приложений необходимо использовать генерацию исходного кода.

Создание источника можно использовать в двух режимах:

  • Режим на основе метаданных

    Во время компиляции System.Text.Json собирает необходимые для сериализации сведения и создает файлы исходного кода, которые заполняют метаданные контрактов JSON для запрошенных типов.

  • Режим оптимизации сериализации (быстрый путь)

    JsonSerializer функции, которые настраивают выходные данные сериализации, такие как политики именования и сохранение ссылок, влияют на производительность. В режиме оптимизации сериализации System.Text.Json генерирует оптимизированный код сериализации, который использует Utf8JsonWriter напрямую. Этот оптимизированный код или ускоренный путь увеличивает пропускную способность сериализации.

    В настоящее время ускоренная десериализация недоступна. Дополнительные сведения см. в статье dotnet/runtime issue 55043.

Для создания источника System.Text.Json требуется C# 9.0 или более поздняя версия.

Note

Поддержка различаемого объединения F# работает только в режиме отражения. Для этого требуется динамический код и необрезанные метаданные отражения. Его нельзя использовать с генерацией исходного кода или Native AOT. Дополнительные сведения см. в разделе F# дискриминированных профсоюзов.

Сравнение возможностей

Выберите режимы отражения или создания источников на основе следующих преимуществ, которые предлагают каждый из них:

Преимущества Отражение Создание источника
(режим на основе метаданных)
Создание источника
(режим оптимизации сериализации)
Проще кодировать. ✔️ ❌ ❌
Удобнее для отладки. ❌ ✔️ ✔️
Поддерживаются [JsonInclude] для непубличных членов. ✔️ ✔️* ✔️*
Поддерживает все доступные настройки сериализации. ✔️ ❌ † ❌ †
Сокращает время запуска. ❌ ✔️ ✔️
Уменьшает использование частной памяти. ❌ ✔️ ✔️
Устраняет отражение среды выполнения. ❌ ✔️ ✔️
Облегчает безопасное сокращение размера приложения. ❌ ✔️ ✔️
Увеличивает пропускную способность сериализации. ❌ ❌ ✔️

* Начиная с .NET 11, генерация исходного кода поддерживает члены private, internal и protected, которые явно помечены атрибутом [JsonInclude]. Он также поддерживает методы доступа private, internal и protected для свойств, которые вы помечаете с помощью [JsonInclude]. Создание источников на основе метаданных поддерживает недоступные конструкторы, помеченные с помощью [JsonConstructor]. Сгенерированные сеттеры вызываются только для свойств только с init, которые присутствуют в JSON, поэтому пропущенные свойства сохраняют значения, заданные инициализатором. В .NET 10 и более ранних версиях генерация исходного кода не поддерживает члены или методы доступа private или protected, а также недоступные конструкторы. Созданный контекст может получать доступ к членам и методам доступа internal только в том случае, если они находятся в одной сборке. Дополнительные сведения см. в разделе Непубличные члены и конструкторы. † Использовать API настройки контракта для изменения исходных контрактов.