Novidades do .NET 7: melhorias na serialização JSON em cenários de polimorfismo
Princípios como herança e polimorfismo são aspectos centrais dentro da disciplina de Orientação a Objetos, constituindo noções importantíssimas em cenários que demandem reaproveitamento de código e uma melhor estruturação de projetos de software. Muitas bibliotecas e funcionalidades são inclusive projetadas tomando por base estes conceitos, o que acaba por exigir um claro entendimento dos mesmos.
O próprio .NET 7 levou em conta os conceitos de herança e polimorfismo, em melhorias envolvendo processos de serialização e desserialização com recursos do namespace System.Text.Json. É o que mostrarei neste novo artigo, que dá continuidade à série de novidades do .NET 7.
Caso queira ficar por dentro dos conteúdos anteriores sobre .NET 7 publicados aqui no blog, acesse o link a seguir:
.NET 7 - Guia de Referência: artigos, vídeos e exemplos de utilização
Supondo as implementações a seguir, em que a classe Aluno herda de Pessoa:
Considerando a serialização de uma instância de Aluno tratada como se fosse uma referência para Pessoa, notaremos que ao final deste processo a variável indicada por pessoa2 é agora uma instância de Pessoa (e não Aluno). Isto aconteceu porque o conteúdo associado à propriedade Curso foi descartado durante a serialização (resultado destacado em vermelho no print):
Numa versão refatorada do exemplo anterior o atributo JsonDerivedType foi associado à classe Pessoa, com a indicação de que instâncias de Aluno correspondem a um tipo derivado que deve ser considerado na serialização:
Isto ainda não resolverá a questão da desserialização (o conteúdo da propriedade Curso foi perdido, já que geramos uma instância de Pessoa), mas podemos notar que a etapa de serialização já reconheceu o tipo da variável pessoa2 como Aluno (variável jsonPessoa2):
Podemos solucionar essa questão preenchendo o atributo typeDiscriminator de JsonDerivedType (namespace System.Text.Json.Serialization), com um identificador específico para cada tipo (a string informada deve representar um valor único):
A serialização acrescentará o campo $type a cada resultado, estando associado ao mesmo o valor de typeDiscriminator. Com isto a desserialização de jsonPessoa2 produzirá uma instância de Aluno:
É possível até mesmo customizar o nome do campo que corresponde ao typeDiscriminator, através do uso do atributo JsonPolymorphic (namespace System.Text.Json.Serialization) e preenchimento de sua propriedade TypeDiscriminatorPropertyName:
Para este exemplo definimos $class como valor do typeDiscriminator, conforme é possível observar nos resultados destacados na imagem a seguir:
Na listagem a seguir temos outras alternativas de uso dos atributos JsonDerivedType e JsonPolymorphic:
- Valores int também podem ser informados em typeDiscriminator, como indicado nas linhas 5 e 6 para os tipos Veiculo e Carro;
- A classe CarroCorrida não foi associada a nenhuma declaração com o atributo JsonDerivedType. Isto poderia acarretar num erro de serialização ao utilizarmos o tipo Veiculo. Para resolver este problema podemos configurar no atributo JsonPolymorphic o valor da propriedade UnknownDerivedTypeHandling com o enumerator JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor, que determina que as regras de serialização assumirão as configurações do ancestral mais próximo (Carro);
- Outras possibilidades para JsonUnknownDerivedTypeHandling são FallBackToBaseType (em que se assumem as configurações do tipo no topo da hierarquia, que neste exemplo seria Veiculo) e FailSerialization (comportamento default, lançando uma exceção caso não haja mapeamento com JsonDerivedType).
Já na próxima listagem temos testes envolvendo serialização e desserialização com os tipos Veiculo, Carro e CarroCorrida. Pelas regras definidas na listagem anterior a instância de CarroCorrida será serializada/desserializada como uma referência do tipo Carro:
É o que demonstram os resultados a seguir:
Os testes apresentados aqui foram disponibilizados em um repositório do GitHub:
https://github.com/renatogroffe/DotNet7-Preview6-ConsoleApp-JsonSerialization-Polymorphism
Caso achem útil a solução, peço por favor um ⭐️ no repositório apoiando. Fica também o convite para que vocês me sigam lá!
E finalizo este artigo com um convite…
Segunda 15/08 às 21:00 — horário de Brasília — teremos mais um evento online e gratuito no canal Canal .NET.
Esta nova live trará dicas, truques e alternativas úteis para o desenvolvimento Back-End e de APIs REST com .NET 6, C#, ASP.NET Core e Azure Functions. Ao longo da apresentação será coberto o uso de diferentes frameworks, serviços na nuvem, mensageria e boas práticas de forma a facilitar e tornar mais dinâmica a implementação de soluções baseadas na plataforma .NET no seu dia a dia.
Teremos também algumas novidades do Visual Studio 2022, .NET 7 e do C# 11 demonstradas na prática!
Para participar faça sua inscrição no link a seguir, a transmissão acontecerá via YouTube: