Samenvoegtypen serialiseren met System.Text.Json

Vanaf .NET 11 worden JsonSerializerC# 15 samenvoegtypen ondersteund. Een union bevat in zijn declaratie een van de varianten. JsonSerializer schrijft de actieve casewaarde en kan deze teruglezen.

Samenvoegwaarden serialiseren en deserialiseren

Definieer een unie waarvan de varianten verschillende JSON-tokentypen hebben:

public union Payload(int, string, Message);
public sealed record Message(string Text);

Gebruik JsonSerializer om de union te serialiseren en deserialiseren:

Payload payload = new Message("Ready");
string json = JsonSerializer.Serialize(payload);
Payload copy = JsonSerializer.Deserialize<Payload>(json);

De geserialiseerde JSON bevat de actieve casewaarde in plaats van een wrapper of discriminator:

{"Text":"Ready"}

Standaard classificeert de serializer binnenkomende JSON op tokentype. In de voorgaande samenvoeging selecteert inteen JSON-getal, een JSON-tekenreeks selecteert stringen selecteert Messageeen JSON-object.

Met JsonSerializerOptions.Web, een int kan ook worden gelezen uit een JSON-tekenreeks. Zowel de gevallen int als string van Payload maken dan aanspraak op het tokentype tekenreeks. Zelfs "25%" genereert JsonException vanwege ambiguïteit voordat de serialisator beide gevallen parseert. Als u tekenreeksen met webstandaardwaarden wilt lezen, geeft u een aangepaste classificator op waarmee de schrijfwijze in hoofd- of kleine letters wordt gekozen.

Onderscheid maken tussen gevallen met hetzelfde JSON-tokentype

Tokenclassificatie kan geen onderscheid maken tussen twee gevallen die beide worden geserialiseerd als JSON-objecten. Toepassen JsonUnionAttribute en selecteren JsonUnionTypeStructuralClassifier om objectcases te classificeren op basis van de eigenschapsnamen:

[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);

JsonUnionAttribute Hier selecteert u een classificatie voor de bestaande Pet samenvoeging. Als u deze toepast op een gewoon type, wordt dat type niet omgezet in een samenvoeging.

De classificatie selecteert Dog wanneer de nettolading bevat Breed en selecteert Cat wanneer deze bevat Lives:

Pet pet = JsonSerializer.Deserialize<Pet>(
    """{"Name":"Rex","Breed":"Husky"}""");

Voor JSON-objecten begint de structurele classifier met de compatibele objecttypen en verkleint die verzameling naarmate herkende eigenschapsnamen op rootniveau worden gelezen. Vereiste eigenschappen sluiten scenario’s uit waarin die ontbreken. JsonUnmappedMemberHandling.Disallow verwijdert een case als de payload een eigenschap bevat die niet in de case is gedeclareerd. Classificatie slaagt alleen als er nog maar één geval overblijft.

De structurele classificatie inspecteert geen eigenschapswaarden, geneste objecten, tekenreeksinhoud of matrixelementen. Houd rekening met deze gevolgen:

  • Een payload die nul of meerdere kandidaten oplevert, genereert JsonException.
  • Overlappende of schaduwobjectcontracten kunnen worden geweigerd wanneer de classificatie wordt gemaakt.
  • Meerdere niet-objectcases die hetzelfde JSON-tokentype gebruiken, worden niet ondersteund. Gebruik bijvoorbeeld Guidstring JSON-tekenreeksen.
  • Een gewone objectcase kan niet worden gecombineerd met een woordenlijst, JsonObjectof een andere niet-POCO-objectvormige case.
  • Geneste samenvoegcases en polymorfe gevallen worden niet ondersteund.
  • ReferenceHandler.Preserve wordt niet ondersteund.
  • Een configuratie die de gevallen niet kan onderscheiden, werpt NotSupportedException wanneer de serialisatiefunctie de classificatie bouwt.

Kies unietypen of gesloten hiërarchieën

Gebruik een samenvoeging wanneer u een JSON-indeling zonder onderscheid wilt behouden die u niet bepaalt of wanneer de gevallen verschillende JSON-shapes hebben. De gevallen string en Payload van int zijn bijvoorbeeld te onderscheiden aan de hand van het JSON-tokentype. Voor objectcases, zoals Pet(Dog, Cat), kunnen wijzigingen in eigenschapsnamen echter van invloed zijn op welk geval een structurele classificatie selecteert.

Wanneer u de typen en het JSON-contract bepaalt, kan een gesloten hiërarchie met afgeleid polymorfisme in plaats daarvan objectcases identificeren met een discriminator:

[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)) schrijft {"$type":"Created","Id":42}. Beide afgeleide typen declareren Id, maar de discriminator identificeert het geval onafhankelijk van de eigenschappen ervan. Hierdoor wordt caseselectie stabieler naarmate de eigenschappen zich ontwikkelen. In tegenstelling tot union-cases moeten de afgeleide typen een basisklasse delen en moet u expliciet kiezen voor afgeleid polymorfisme; de modifier closed alleen voegt geen discriminator toe.

Een aangepaste classificatie opgeven

Leid af van JsonTypeClassifierFactory wanneer standaard tokenclassificatie of de ingebouwde JsonUnionTypeStructuralClassifier niet aan uw vereisten voldoet. Een aangepaste classificatie kan andere structurele regels gebruiken om een samenvoegcase te selecteren. Registreer de fabriek op een van deze locaties:

Een classificatie leest de huidige JSON-waarde en retourneert een van de casetypen van JsonTypeClassifierContext.UnionCases. De serializer controleert eerst de gemachtigde van het contract, gevolgd door de fabriek per unie, de factory's op optiesniveau en de ingebouwde tokenclassificatie.

Voor dubbelzinnige samenvoegingen rapporteert de brongenerator een diagnose, tenzij een classificatie tijdens het genereren is geconfigureerd.

Null- en standaard samenvoegwaarden verwerken

Een samenvoeging kan null-casetypen declareren. JSON null selecteert de eerste nullable case. Als de samenvoeging geen nullable case heeft, produceert JSON null de standaard-samenvoegwaarde. Voor een door de compiler gegenereerde struct-unie heeft de standaardwaarde geen actieve variant en wordt deze als JSON null geserialiseerd.

Uniecontract aanpassen

Voor geavanceerde scenario's past u de metagegevens van de samenvoeging aan via JsonTypeInfo. De waarde van JsonTypeInfo.Kind een samenvoeging is JsonTypeInfoKind.Union. Het contract laat het volgende zien:

Zie JsonTypeInfo voor meer informatie over het aanpassen van .

Zie ook