Modes de génération de source dans System.Text.Json
La génération de source peut être utilisée dans deux modes : l’optimisation basée sur les métadonnées et la sérialisation. Cet article présente les différents modes.
Pour plus d’informations sur l’utilisation des modes de génération source, consultez Comment utiliser la génération source dans System.Text.Json.
Mode basé sur les métadonnées
Vous pouvez utiliser la génération de source pour déplacer le processus de collecte de métadonnées du moment de l’exécution au moment de la compilation. Pendant la compilation, les métadonnées sont collectées et les fichiers de code source sont générés. Les fichiers de code source générés sont automatiquement compilés en tant que partie intégrante de l’application. Cette technique élimine la collecte de métadonnées au moment de l’exécution, ce qui améliore les performances de la sérialisation et de la désérialisation.
Les améliorations de performances apportées par la génération de source peuvent être substantielles. Par exemple, les résultats des tests ont montré jusqu’à 40 % ou plus de réduction du temps de démarrage, une réduction de la mémoire privée, une augmentation de la vitesse de débit (en mode d’optimisation de la sérialisation) et une réduction de la taille de l’application.
Problèmes connus
Seuls les champs et propriétés public
sont pris en charge par défaut dans l’un ou l’autre des modes de sérialisation. Toutefois, le mode de réflexion prend en charge l’utilisation d’accesseurs private
, contrairement au mode de génération de source. Par exemple, vous pouvez appliquer l’attribut JsonInclude à une propriété qui a un setter ou getter private
et qui sera sérialisée en mode réflexion. Le mode de génération de source prend en charge uniquement les accesseurs public
ou internal
des propriétés public
. Si vous définissez [JsonInclude]
sur des accesseurs non publics et que vous choisissez le mode de génération de source, une NotSupportedException
est levée au moment de l’exécution.
Seuls les champs et propriétés public
sont pris en charge par défaut dans l’un ou l’autre des modes de sérialisation. Toutefois, le mode de réflexion prend en charge l’utilisation de membres private
et d’accesseurs private
, contrairement au mode de génération de source. Par exemple, vous pouvez appliquer l’attribut JsonInclude à une propriété private
ou à une propriété qui a un setter ou getter private
, il sera sérialisé en mode réflexion. Le mode de génération de source prend en charge uniquement les membres public
ou internal
et les accesseurs public
ou internal
des propriétés public
. Si vous définissez [JsonInclude]
sur des membres ou des accesseurs private
et que vous choisissez le mode de génération de source, une NotSupportedException
est levée au moment de l’exécution.
Pour plus d’informations sur les autres problèmes connus liés à la génération de source, consultez les problèmes GitHub étiquetés « source-generator » dans le référentiel dotnet/runtime.
Mode d’optimisation de la sérialisation (chemin rapide)
JsonSerializer
possède de nombreuses fonctionnalités qui personnalisent la sortie de la sérialisation, comme les stratégies d’affectation de noms et la conservation des références. La prise en charge de toutes ces fonctionnalités entraîne une certaine surcharge de performances. La génération de source peut améliorer les performances de sérialisation en générant du code optimisé qui utilise Utf8JsonWriter
directement.
Le code optimisé ne prend pas en charge toutes les fonctionnalités de sérialisation que JsonSerializer
prend en charge. Le sérialiseur détecte si le code optimisé peut être utilisé et revient au code de sérialisation par défaut si des options non prises en charge sont spécifiées. Par exemple, JsonNumberHandling.AllowReadingFromString n’étant pas applicable à l’écriture, la spécification de cette option n’entraîne pas un retour vers le code par défaut.
Le tableau suivant indique les options de JsonSerializerOptions
prises en charge par la sérialisation à chemin rapide :
Option de sérialisation | Prise en charge pour le chemin rapide |
---|---|
AllowTrailingCommas | ✔️ |
Converters | ❌ |
DefaultBufferSize | ✔️ |
DefaultIgnoreCondition | ✔️ |
DictionaryKeyPolicy | ❌ |
Encoder | ❌ |
IgnoreNullValues | ❌ |
IgnoreReadOnlyFields | ✔️ |
IgnoreReadOnlyProperties | ✔️ |
IncludeFields | ✔️ |
MaxDepth | ✔️ |
NumberHandling | ❌ |
PropertyNamingPolicy | ✔️ |
ReferenceHandler | ❌ |
TypeInfoResolver | ✔️ |
WriteIndented | ✔️ |
(Les options suivantes ne sont pas prises en charge, car elles s’appliquent uniquement à la désérialisation : PropertyNameCaseInsensitive, ReadCommentHandling et UnknownTypeHandling.)
Le tableau suivant indique les attributs pris en charge par la sérialisation à chemin rapide :
Attribut | Prise en charge pour le chemin rapide |
---|---|
JsonConstructorAttribute | ❌ |
JsonConverterAttribute | ❌ |
JsonDerivedTypeAttribute | ✔️ |
JsonExtensionDataAttribute | ❌ |
JsonIgnoreAttribute | ✔️ |
JsonIncludeAttribute | ✔️ |
JsonNumberHandlingAttribute | ❌ |
JsonPolymorphicAttribute | ✔️ |
JsonPropertyNameAttribute | ✔️ |
JsonPropertyOrderAttribute | ✔️ |
JsonRequiredAttribute | ✔️ |
Si une option ou un attribut non pris en charge est spécifié pour un type, le sérialiseur revient au mode de métadonnées, en supposant que le générateur de source a été configuré pour générer des métadonnées. Dans ce cas, le code optimisé n’est pas utilisé lors de la sérialisation de ce type, mais peut être utilisé pour d’autres types. Par conséquent, il est important d’effectuer des tests de performance avec vos options et charges de travail pour déterminer les avantages que vous pouvez réellement tirer du mode d’optimisation de la sérialisation. En outre, la possibilité de revenir au code JsonSerializer
nécessite le mode de collection de métadonnées. Si vous sélectionnez uniquement le mode d’optimisation de la sérialisation, cette dernière peut échouer pour les types ou les options qui doivent revenir au code JsonSerializer
.