Modos de geração de fonte em System.Text.Json

A geração de origem pode ser usada em dois modos: baseado em metadados e otimização de serialização. Este artigo descreve os diferentes modos.

Para obter informações sobre como usar os modos de geração de origem, consulte Como usar a geração de origem no System.Text.Json.

Modo baseado em metadados

Pode usar a geração de origem para mover o processo de recolha de metadados do tempo de execução para o tempo de compilação. Durante a compilação, os metadados são coletados e os arquivos de código-fonte são gerados. Os arquivos de código-fonte gerados são compilados automaticamente como parte integrante do aplicativo. Esta técnica elimina a recolha de metadados em tempo de execução, o que melhora o desempenho tanto da serialização como da desserialização.

As melhorias de desempenho proporcionadas pela geração de origem podem ser substanciais. Por exemplo, os resultados do teste mostraram até 40% ou mais de redução do tempo de inicialização, redução da memória privada, aumento da velocidade de transferência (no modo de otimização de serialização) e redução do tamanho do aplicativo.

Membros não públicos e construtores

Por defeito, tanto o modo de reflexão como o modo de geração a partir da origem incluem apenas as propriedades e os campos public no contrato de serialização.

A partir do .NET 11, a geração de código-fonte suporta membros que assinala explicitamente com o atributo [JsonInclude]. O membro pode ser private, internal, ou protected. Também suporta acessores private, internal e protected em propriedades que marcar com [JsonInclude]. A geração de código-fonte também suporta construtores inacessíveis marcados com [JsonConstructor].

No .NET 11, os acessores gerados usam UnsafeAccessorAttribute.

Um método set gerado pelo código-fonte para uma propriedade só de init só é executado quando o payload JSON contém essa propriedade. Uma propriedade apenas de init cuja payload é omitida mantém o valor do inicializador da propriedade.

No .NET 10 e versões anteriores, a geração de código-fonte apresenta as seguintes limitações:

  • A geração de código não suporta membros ou acessores private ou protected. Se marcar esse membro com [JsonInclude], o serializador lança NotSupportedException em tempo de execução.
  • A geração de código suporta membros e acessores internal apenas quando estão acessíveis ao JsonSerializerContext gerado na mesma assemblagem.
  • A geração de fonte não suporta construtores inacessíveis ao contexto gerado, mesmo quando os marca com [JsonConstructor].

Problemas conhecidos

Para obter informações sobre outros problemas conhecidos com a geração de código-fonte, consulte os problemas do GitHub rotulados como "gerador de código-fonte" no repositório dotnet/runtime .

Modo de otimização de serialização (caminho rápido)

JsonSerializer tem muitos recursos que personalizam a saída da serialização, como políticas de nomenclatura e preservação de referências. O suporte para todos esses recursos causa alguma sobrecarga de desempenho. A geração de código-fonte pode melhorar o desempenho da serialização gerando código otimizado que usa Utf8JsonWriter diretamente.

O modo de otimização de serialização emite métodos de serialização de caminho rápido, mas não metadados de serialização. A serialização de caminho rápido é restrita no que pode fazer; ele não suporta serialização assíncrona ou qualquer modo de desserialização.

Além disso, o código otimizado não suporta todos os recursos de serialização suportados JsonSerializer . O serializador deteta se o código otimizado pode ser usado e retorna ao código de serialização padrão se opções sem suporte forem especificadas. Por exemplo, JsonNumberHandling.AllowReadingFromString não é aplicável à escrita, portanto, especificar essa opção não causa um fallback para o código padrão.

A tabela a seguir mostra quais opções no JsonSerializerOptions são suportadas pela serialização de caminho rápido.

Opção de serialização Suportado para fast-path
AllowTrailingCommas ✔️
Converters ❌
DefaultBufferSize ✔️
DefaultIgnoreCondition ✔️
DictionaryKeyPolicy ❌
Encoder ❌
IgnoreNullValues ❌
IgnoreReadOnlyFields ✔️
IgnoreReadOnlyProperties ✔️
IncludeFields ✔️
MaxDepth ✔️
NumberHandling ❌
PropertyNamingPolicy ✔️
ReferenceHandler ❌
TypeInfoResolver ✔️
WriteIndented ✔️

(As seguintes opções não são suportadas porque se aplicam apenas à desserialização: PropertyNameCaseInsensitive, ReadCommentHandling e UnknownTypeHandling.)

A tabela a seguir mostra quais atributos são suportados pela serialização de caminho rápido:

Atributo Suportado para fast-path
JsonConstructorAttribute ❌
JsonConverterAttribute ❌
JsonDerivedTypeAttribute ✔️
JsonExtensionDataAttribute ❌
JsonIgnoreAttribute ✔️
JsonIncludeAttribute ✔️
JsonNumberHandlingAttribute ❌
JsonPolymorphicAttribute ✔️
JsonPropertyNameAttribute ✔️
JsonPropertyOrderAttribute ✔️
JsonRequiredAttribute ✔️

Se uma opção ou atributo sem suporte for especificado para um tipo, o serializador retornará ao modo de metadados, supondo que o gerador de origem tenha sido configurado para gerar metadados. Nesse caso, o código otimizado não é usado ao serializar esse tipo, mas pode ser usado para outros tipos. Portanto, é importante fazer testes de desempenho com as suas opções e cargas de trabalho para determinar quanto benefício pode realmente obter do modo de otimização da serialização. Além disso, a capacidade de voltar ao JsonSerializer código requer o modo de metadados. Se selecionar apenas o modo de otimização de serialização, a serialização poderá falhar para tipos ou opções que precisam reverter para o JsonSerializer código.

Consulte também