Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
A partir do .NET 11, JsonSerializer dá suporte a tipos de união C# 15. Uma união contém um dos tipos de caso em sua declaração.
JsonSerializer grava o valor de caso ativo e pode lê-lo novamente.
Serializar e desserializar valores de união
Declare uma união cujos casos têm tipos de token JSON distintos:
public union Payload(int, string, Message);
public sealed record Message(string Text);
Use JsonSerializer para serializar e desserializar a união:
Payload payload = new Message("Ready");
string json = JsonSerializer.Serialize(payload);
Payload copy = JsonSerializer.Deserialize<Payload>(json);
O JSON serializado contém o valor de caso ativo em vez de um wrapper ou discriminador:
{"Text":"Ready"}
Por padrão, o serializador classifica o JSON de entrada por tipo de token. Na união anterior, um número JSON seleciona int, uma string JSON seleciona string e um objeto JSON seleciona Message.
Com JsonSerializerOptions.Web, um int também pode ser lido de uma cadeia de caracteres JSON. Tanto o caso string quanto o caso int de Payload passam então a assumir o tipo de token de string. Até mesmo "25%" gera JsonException devido à ambiguidade antes que o serializador analise qualquer um dos casos. Para ler cadeias de caracteres com padrões da Web, forneça um classificador personalizado que escolha o caso.
Distinguir casos com o mesmo tipo de token JSON
A classificação de tokens não consegue distinguir dois casos serializados como objetos JSON. Aplique JsonUnionAttribute e selecione JsonUnionTypeStructuralClassifier para classificar casos de objeto por seus nomes de propriedade:
[JsonUnion(TypeClassifier = typeof(JsonUnionTypeStructuralClassifier))]
public union Pet(Dog, Cat);
public sealed record Dog(string Name, string Breed);
public sealed record Cat(string Name, int Lives);
Aqui, JsonUnionAttribute seleciona um classificador para a união existente Pet ; aplicá-lo a um tipo comum não transforma esse tipo em uma união.
O classificador seleciona Dog quando o conteúdo contém Breed e seleciona Cat quando contém Lives:
Pet pet = JsonSerializer.Deserialize<Pet>(
"""{"Name":"Rex","Breed":"Husky"}""");
Para objetos JSON, o classificador estrutural começa com os casos compatíveis de objeto e vai restringindo esse conjunto à medida que lê nomes de propriedades reconhecidos no nível raiz. Propriedades obrigatórias removem casos quando estão ausentes. JsonUnmappedMemberHandling.Disallow remove um caso quando o payload contém uma propriedade que o caso não declara. A classificação só é bem-sucedida quando um caso permanece.
O classificador estrutural não inspeciona valores de propriedade, objetos aninhados, conteúdo de cadeia de caracteres ou elementos de matriz. Tenha estas consequências em mente:
- Uma carga útil que resulta em zero ou vários candidatos gera JsonException.
- Contratos de objetos sobrepostos ou sombreados podem ser rejeitados quando o classificador é criado.
- Não há suporte para vários casos que não sejam de objeto que usam o mesmo tipo de token JSON. Por exemplo,
Guidestringambos usam cadeias de caracteres JSON. - Um caso de objeto simples não pode ser combinado com um dicionário,
JsonObject, nem com outro caso com formato de objeto que não seja POCO. - Não há suporte para casos de união aninhados e casos polimórficos.
- Não há suporte para ReferenceHandler.Preserve.
- Uma configuração que não consegue distinguir seus casos lança NotSupportedException quando o serializador cria o classificador.
Escolher uniões ou hierarquias fechadas
Use uma união quando precisar preservar um formato JSON sem discriminadores que você não controla ou quando os casos tiverem formas JSON distintas. Por exemplo, os casos string e int de Payload são distinguíveis pelo tipo de token JSON. Para casos de objeto, como Pet(Dog, Cat), no entanto, alterações em nomes de propriedade podem afetar o caso em que um classificador estrutural seleciona.
Quando você controla os tipos e o contrato JSON, uma hierarquia fechada com polimorfismo inferido pode identificar tipos de objeto com um discriminador, em vez disso:
[JsonPolymorphic(InferClosedTypePolymorphism = true)]
public closed record Event;
public sealed record Created(int Id) : Event;
public sealed record Deleted(int Id) : Event;
JsonSerializer.Serialize<Event>(new Created(42)) escreve {"$type":"Created","Id":42}. Ambos os tipos derivados declaram Id, mas o discriminador identifica o caso independentemente de suas propriedades. Isso torna a seleção de casos mais estável à medida que as propriedades evoluem. Ao contrário dos casos de união, os tipos derivados devem compartilhar uma classe base e você deve aceitar o polimorfismo inferido; o closed modificador sozinho não adiciona um discriminador.
Fornecer um classificador personalizado
Derive de JsonTypeClassifierFactory quando a classificação de token padrão ou a JsonUnionTypeStructuralClassifier integrada não atenderem aos seus requisitos. Um classificador personalizado pode usar outras regras estruturais para selecionar um caso de união. Registre a fábrica em um destes locais:
- Atribua um delegado a JsonTypeInfo.TypeClassifier ao personalizar o contrato.
- Defina JsonUnionAttribute.TypeClassifier para uma união.
- Adicione a fábrica a JsonSerializerOptions.TypeClassifiers para serialização baseada em reflexão.
- Defina JsonSourceGenerationOptionsAttribute.TypeClassifiers para um contexto de geração de código-fonte.
Um classificador lê o valor JSON atual e retorna um dos tipos de caso de JsonTypeClassifierContext.UnionCases. O serializador verifica primeiro o delegado de contrato, seguido pela fábrica específica de cada união, pelas fábricas definidas no nível das opções e pela classificação interna de tokens.
Para uniões ambíguas, o gerador de código-fonte emite um diagnóstico, a menos que um classificador seja configurado durante a geração.
Lidar com valores nulos e valores de união padrão
Uma união pode declarar tipos de caso anuláveis. O JSON null seleciona o primeiro caso anulável. Se a união não tiver nenhum caso anulável, o JSON null produzirá o valor de união padrão. Para uma união de struct gerada pelo compilador, o valor padrão não tem nenhum caso ativo e é serializado como JSON null.
Personalizar um contrato de união
Para cenários avançados, personalize os metadados da união por meio de JsonTypeInfo. O valor de uma união JsonTypeInfo.Kind é JsonTypeInfoKind.Union. Seu contrato expõe:
- JsonTypeInfo.UnionCases, que contém JsonUnionCaseInfo entradas.
- JsonTypeInfo.UnionConstructor, que cria uma união com base em um tipo de caso e um valor.
- JsonTypeInfo.UnionDeconstructor, que retorna o tipo de caso ativo e o valor.
- JsonTypeInfo.TypeClassifier, que seleciona um caso durante a desserialização.
Para obter mais informações sobre como modificar JsonTypeInfo, consulte Personalizar um contrato JSON.