Megosztás a következőn keresztül:


Inicializált tulajdonságok feltöltése

A .NET 8-tól kezdve megadhatja, hogy a JSON deszerializálásakor a .NET-tulajdonságokat cserélje le vagy töltse fel . Az JsonObjectCreationHandling enumerálás biztosítja az objektumlétrehozási kezelési lehetőségeket:

Alapértelmezett (csere) viselkedés

A System.Text.Json deszerializáló mindig létrehoz egy új példányt a céltípushoz. Annak ellenére, hogy új példány jön létre, előfordulhat, hogy egyes tulajdonságok és mezők már inicializálva vannak az objektum konstrukciójának részeként. Vegye figyelembe a következő típust:

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

Az osztály egy példányának létrehozásakor a Numbers1 (és Numbers2) tulajdonság értéke egy három elemet (1, 2 és 3) tartalmazó lista. Ha a JSON-t ilyen típusúra deszerializálja, az alapértelmezett viselkedés az, hogy a tulajdonságértékek lecserélődnek:

  • Mivel Numbers1írásvédett (nincs beállító), továbbra is az 1, a 2 és a 3 érték szerepel a listában.
  • Az olvasási-írási értékhez Numbers2egy új lista lesz lefoglalva, és hozzáadja a JSON-ból származó értékeket.

Ha például a következő deszerializálási kódot hajtja végre, az 1, Numbers1 a 2 és a 3 értéket, valamint Numbers2 a 4, 5 és 6 értéket tartalmazza.

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

Viselkedés feltöltése

A .NET 8-tól kezdve a deszerializálási viselkedést módosíthatja a tulajdonságok és mezők módosítása (feltöltése) helyett:

  • Gyűjtemény típusú tulajdonság esetén az objektum törlés nélkül újra felhasználható. Ha a gyűjtemény előre feltöltve van elemekkel, akkor a végső deszerializált eredményben jelennek meg a JSON értékeivel együtt. Példaként lásd a Gyűjtemény tulajdonság példáját.

  • A tulajdonsággal rendelkező objektumok esetében a rendszer frissíti a változó tulajdonságait a JSON-értékekre, de maga az objektumhivatkozás nem változik.

  • A struct típusú tulajdonság esetében a tényleges viselkedés az, hogy a rendszer megőrzi a meglévő értékeket, és új értékeket ad hozzá a JSON-ból. A referenciatulajdonságokkal ellentétben azonban maga az objektum nem lesz újra felhasználva, mivel értéktípus. Ehelyett a rendszer módosítja a szerkezet egy példányát, majd újból hozzárendeli a tulajdonsághoz. Példaként lásd a Struct tulajdonság példáját.

    A szerkezettulajdonságoknak elválasztóval kell rendelkezniük; ellenkező esetben a InvalidOperationException rendszer futásidőben dob.

Feljegyzés

A feltöltési viselkedés jelenleg nem működik paraméteres konstruktort tartalmazó típusok esetében. További információ: dotnet/runtime issue 92877.

Csak olvasható tulajdonságok

A nem módosítható referenciatulajdonságok feltöltéséhez, mivel a tulajdonsághivatkozásokat tartalmazó példányt nem cseréli le, a tulajdonságnak nem kell beállítóval rendelkeznie. Ez a viselkedés azt jelenti, hogy a deszerializálás írásvédett tulajdonságokat is feltölthet.

Feljegyzés

A szerkezettulajdonságokhoz továbbra is szükség van a beállítókra, mert a példányt módosított másolatra cseréli a rendszer.

Példa gyűjteménytulajdonságra

Vegye figyelembe ugyanezt az osztályt A a helyettesítési viselkedési példában, de ezúttal ahelyett, hogy lecserélné őket, az előugró tulajdonságokat részesíti előnyben:

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

Ha a következő deszerializálási kódot hajtja végre, az Numbers2 1, Numbers1 2, 3, 4, 5 és 6 értéket tartalmazza:

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

Példa a Struct tulajdonságra

Az alábbi osztály tartalmaz egy struct tulajdonságot, S1amelynek deszerializálási viselkedése a következőre Populatevan állítva. A kód c.S1.Value1 végrehajtása után a kód értéke 10 (a konstruktorból), és c.S1.Value2 értéke 5 (a JSON-ból).

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; }
}

Ha ehelyett az alapértelmezett Replace viselkedést használná, c.S1.Value1 az alapértelmezett értéke 0 lenne a deszerializálás után. Ennek az az oka, c.S1.Value1 hogy a konstruktor C() neve 10 lesz, de az S1 értékét lecseréli egy új példányra. (c.S1.Value2 továbbra is 5, mivel a JSON az alapértelmezett értéket helyettesíti.)

A beállítás menete

A csere vagy feltöltés beállításának többféle módja is van:

  • JsonObjectCreationHandlingAttribute Az attribútummal a típus vagy a tulajdonság szintjén jegyzetelhet. Ha az attribútumot a típus szintjén állítja be, és annak tulajdonságát Populateállítja Handling be, a viselkedés csak azokra a tulajdonságokra lesz érvényes, amelyekben a sokaság lehetséges (például az értéktípusoknak elválasztóval kell rendelkezniük).

    Ha azt szeretné, hogy a típusszintű beállítás legyen Populate, de ki szeretne zárni egy vagy több tulajdonságot ebből a viselkedésből, az örökölt viselkedés felülbírálása érdekében hozzáadhatja az attribútumot a típus szintjén, majd ismét a tulajdonság szintjén. Ez a minta az alábbi kódban jelenik meg.

    // 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];
    }
    
  • Állítsa be JsonSerializerOptions.PreferredObjectCreationHandling (vagy a forrásgeneráláshoz JsonSourceGenerationOptionsAttribute.PreferredObjectCreationHandling) a globális beállítások megadásához.

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