Réflexion par rapport à génération de source dans System.Text.Json

Cet article explique les différences entre la réflexion et la génération de source en ce qui concerne la sérialisation System.Text.Json. Il fournit également des conseils sur la façon de choisir la meilleure approche pour votre scénario.

Collection de métadonnées

Pour sérialiser ou désérialiser un type, JsonSerializer a besoin d’informations sur la façon d’accéder aux membres du type. JsonSerializer a besoin des informations suivantes :

  • Comment accéder aux getters de propriétés et aux champs pour la sérialisation.
  • Comment accéder à un constructeur, à des setters de propriétés et à des champs pour la désérialisation.
  • Informations sur les attributs utilisés pour personnaliser la sérialisation ou la désérialisation.
  • Configuration du runtime à partir de JsonSerializerOptions.

Ces informations sont appelées métadonnées.

Réflexion

Par défaut, JsonSerializer collecte les métadonnées au moment de l’exécution à l’aide de la réflexion. Chaque fois que JsonSerializer doit sérialiser ou désérialiser un type pour la première fois, il collecte et met en cache ces métadonnées. Le processus de collecte de métadonnées prend du temps et utilise de la mémoire.

Génération de la source

En guise d’alternative, System.Text.Json peut utiliser la fonctionnalité de génération de source C# pour améliorer les performances, réduire l’utilisation de la mémoire privée et faciliter le découpage d’assembly, ce qui réduit la taille de l’application. En outre, certaines API de réflexion ne peuvent pas être utilisées dans des applications AOA natives. Vous devez donc utiliser la génération de source pour ces applications.

La génération de source peut être utilisée dans deux modes :

  • Mode basé sur les métadonnées

    Lors de la compilation, System.Text.Json collecte les informations nécessaires à la sérialisation et génère des fichiers de code source qui remplissent les métadonnées de contrat JSON pour les types demandés.

  • Mode d’optimisation de la sérialisation (chemin rapide)

    Les fonctionnalités JsonSerializer qui personnalisent la sortie de la sérialisation, telles que les stratégies de nommage et la préservation des références, ont un impact sur les performances. En mode d’optimisation de la sérialisation, System.Text.Json génère un code de sérialisation optimisé qui utilise Utf8JsonWriter directement. Ce code optimisé ou à chemin rapide augmente le débit de sérialisation.

    La désérialisation à chemin rapide n’est actuellement pas disponible. Pour obtenir plus d’informations, consultez Problème dotnet/runtime 55043.

La génération de source pour System.Text.Json nécessite C# 9.0 ou une version ultérieure.

Note

La prise en charge des unions discriminées F# fonctionne uniquement en mode de réflexion. Il nécessite du code dynamique et des métadonnées de réflexion nontrimmées. Vous ne pouvez pas l’utiliser avec la génération source ou l’AOT natif. Pour plus d’informations, consultez les unions discriminées F#.

Comparaison des fonctionnalités

Choisissez des modes de réflexion ou de génération de source en fonction des avantages suivants offerts par chacun d’eux :

Avantage Réflexion Génération de la source
(mode basé sur les métadonnées)
Génération de la source
(Mode d'optimisation de la sérialisation)
Plus simple à coder. ✔️ ❌ ❌
Plus simple à déboguer. ❌ ✔️ ✔️
Prend en charge [JsonInclude] les membres non publics. ✔️ ✔️* ✔️*
Prend en charge toutes les personnalisations de sérialisation disponibles. ✔️ ❌ † ❌ †
Réduit le temps de démarrage. ❌ ✔️ ✔️
Réduit l’utilisation de la mémoire privée. ❌ ✔️ ✔️
Élimine la réflexion runtime. ❌ ✔️ ✔️
Facilite la réduction de la taille de l’application avec découpage sécurisé. ❌ ✔️ ✔️
Augmente le débit de sérialisation. ❌ ❌ ✔️

* À compter de .NET 11, la génération source prend en charge private, internalet protected les membres que vous marquez explicitement avec [JsonInclude]. Il prend également en charge les accesseurs private, internal et protected pour les propriétés que vous annotez avec [JsonInclude]. La génération de source basée sur les métadonnées prend en charge les constructeurs inaccessibles que vous marquez avec [JsonConstructor]. Les setters générés s’exécutent uniquement pour les propriétés init qui figurent dans le JSON ; les propriétés omises conservent donc leurs valeurs d’initialisation. Dans .NET 10 et les versions antérieures, la génération de code source ne prend pas en charge les membres ou accesseurs private ou protected, ni les constructeurs inaccessibles. Le contexte généré ne peut accéder aux membres et aux accesseurs internal que lorsqu’ils appartiennent au même assembly. Pour plus d’informations, consultez Membres et constructeurs non publics. † Utiliser l’API de personnalisation de contrat pour modifier les contrats générés par la source.