Share via


Geïnitialiseerde eigenschappen vullen

Vanaf .NET 8 kunt u een voorkeur opgeven om .NET-eigenschappen te vervangen of te vullen wanneer JSON wordt gedeserialiseerd. De JsonObjectCreationHandling opsomming biedt de verwerkingsopties voor het maken van objecten:

Standaardgedrag (vervangen)

De System.Text.Json deserializer maakt altijd een nieuw exemplaar van het doeltype. Hoewel er echter een nieuw exemplaar wordt gemaakt, kunnen sommige eigenschappen en velden al worden geïnitialiseerd als onderdeel van de constructie van het object. Houd rekening met het volgende type:

class A
{
    public List<int> Numbers1 { get; } = [1, 2, 3];
    public List<int> Numbers2 { get; set; } = [1, 2, 3];
}

Wanneer u een exemplaar van deze klasse maakt, is de waarde van de Numbers1 eigenschap (en Numbers2) een lijst met drie elementen (1, 2 en 3). Als u JSON deserialiseert voor dit type, is het standaardgedrag dat eigenschapswaarden worden vervangen:

  • Omdat Numbers1het alleen-lezen is (geen setter), heeft het nog steeds de waarden 1, 2 en 3 in de lijst.
  • Voor Numbers2, wat lezen/schrijven is, wordt een nieuwe lijst toegewezen en worden de waarden van de JSON toegevoegd.

Als u bijvoorbeeld de volgende deserialisatiecode uitvoert, Numbers1 bevat u de waarden 1, 2 en 3 en Numbers2 de waarden 4, 5 en 6.

A? a = JsonSerializer.Deserialize<A>("""{"Numbers1": [4,5,6], "Numbers2": [4,5,6]}""");

Gedrag vullen

Vanaf .NET 8 kunt u het gedrag van deserialisatie wijzigen om eigenschappen en velden te wijzigen (vullen) in plaats van deze te vervangen:

  • Voor een eigenschap van het verzamelingstype wordt het object opnieuw gebruikt zonder te wissen. Als de verzameling vooraf wordt ingevuld met elementen, worden deze weergegeven in het uiteindelijke gedeserialiseerde resultaat, samen met de waarden uit de JSON. Zie voorbeeld van verzamelingseigenschap voor een voorbeeld.

  • Voor een eigenschap die een object met eigenschappen is, worden de onveranderbare eigenschappen bijgewerkt naar de JSON-waarden, maar de objectverwijzing zelf verandert niet.

  • Voor een structtype-eigenschap is het effectieve gedrag dat voor de onveranderbare eigenschappen eventuele bestaande waarden worden bewaard en nieuwe waarden uit de JSON worden toegevoegd. In tegenstelling tot een verwijzingseigenschap wordt het object zelf echter niet opnieuw gebruikt omdat het een waardetype is. In plaats daarvan wordt een kopie van de struct gewijzigd en vervolgens opnieuw toegewezen aan de eigenschap. Zie het voorbeeld van de Struct-eigenschap voor een voorbeeld.

    Een struct-eigenschap moet een setter hebben; anders wordt er een InvalidOperationException tijdens runtime gegenereerd.

Notitie

Het vulgedrag werkt momenteel niet voor typen met een geparameteriseerde constructor. Zie dotnet/runtime-probleem 92877 voor meer informatie.

Alleen-lezen eigenschappen

Voor het invullen van verwijzingseigenschappen die kunnen worden gedempt, omdat het exemplaar dat door de eigenschap wordt verwezen niet wordt vervangen, hoeft de eigenschap geen setter te hebben. Dit gedrag betekent dat deserialisatie ook alleen-lezeneigenschappen kan vullen.

Notitie

Struct-eigenschappen vereisen nog steeds setters omdat het exemplaar wordt vervangen door een gewijzigde kopie.

Voorbeeld van verzamelingseigenschap

Houd rekening met dezelfde klasse A uit het voorbeeld van het vervangingsgedrag , maar deze keer een aantekening met een voorkeur voor het invullen van eigenschappen in plaats van deze te vervangen:

[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
class A
{
    public List<int> Numbers1 { get; } = [1, 2, 3];
    public List<int> Numbers2 { get; set; } = [1, 2, 3];
}

Als u de volgende deserialisatiecode uitvoert, bevatten Numbers2 beide Numbers1 de waarden 1, 2, 3, 4, 5 en 6:

A? a = JsonSerializer.Deserialize<A>("""{"Numbers1": [4,5,6], "Numbers2": [4,5,6]}""");

Voorbeeld van Struct-eigenschap

De volgende klasse bevat een struct-eigenschap, S1waarvan het deserialisatiegedrag is ingesteld op Populate. Nadat u deze code hebt uitgevoerd, c.S1.Value1 heeft u de waarde 10 (van de constructor) en c.S1.Value2 een waarde van 5 (van de JSON).

C? c = JsonSerializer.Deserialize<C>("""{"S1": {"Value2": 5}}""");

class C
{
    public C()
    {
        _s1 = new S
        {
            Value1 = 10
        };
    }

    private S _s1;

    [JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
    public S S1
    {
        get { return _s1; }
        set { _s1 = value; }
    }
}

struct S
{
    public int Value1 { get; set; }
    public int Value2 { get; set; }
}

Als het standaardgedrag Replace in plaats daarvan werd gebruikt, c.S1.Value1 zou de standaardwaarde 0 hebben na deserialisatie. Dat komt doordat de constructor C() wordt aangeroepen, ingesteld op c.S1.Value1 10, maar vervolgens wordt de waarde van S1 vervangen door een nieuw exemplaar. (c.S1.Value2 is nog steeds 5, omdat de JSON de standaardwaarde vervangt.)

Opgeven

Er zijn meerdere manieren om een voorkeur op te geven voor vervangen of vullen:

  • Gebruik het JsonObjectCreationHandlingAttribute kenmerk om aantekeningen te maken op type- of eigenschapsniveau. Als u het kenmerk instelt op het typeniveau en de eigenschap Populateinstelt Handling op, is het gedrag alleen van toepassing op de eigenschappen waar de populatie mogelijk is (bijvoorbeeld waardetypen moeten een setter hebben).

    Als u de voorkeur Populatevoor het hele type wilt gebruiken, maar een of meer eigenschappen van dat gedrag wilt uitsluiten, kunt u het kenmerk toevoegen op het typeniveau en opnieuw op eigenschapsniveau om het overgenomen gedrag te overschrijven. Dit patroon wordt weergegeven in de volgende code.

    // Type-level preference is Populate.
    [JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
    class B
    {
        // For this property only, use Replace behavior.
        [JsonObjectCreationHandling(JsonObjectCreationHandling.Replace)]
        public List<int> Numbers1 { get; } = [1, 2, 3];
        public List<int> Numbers2 { get; set; } = [1, 2, 3];
    }
    
  • Stel JsonSerializerOptions.PreferredObjectCreationHandling (of, voor het genereren van de bron) JsonSourceGenerationOptionsAttribute.PreferredObjectCreationHandlingin om een globale voorkeur op te geven.

    var options = new JsonSerializerOptions
    {
        PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate
    };