Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Počínaje .NET 8 můžete zadat předvolbu nahradit nebo naplnit vlastnosti .NET při deserializaci JSON. Výčet JsonObjectCreationHandling poskytuje způsoby, jak zpracovat vytváření objektů:
Výchozí chování (nahrazení)
System.Text.Json Deserializátor vždy vytvoří novou instanci cílového typu. I když je však vytvořena nová instance, některé vlastnosti a pole již mohou být inicializovány jako součást konstrukce objektu. Zvažte následující typ:
class A
{
public List<int> Numbers1 { get; } = [1, 2, 3];
public List<int> Numbers2 { get; set; } = [1, 2, 3];
}
Při vytváření instance této třídy je hodnota vlastnosti Numbers1 (a Numbers2) seznam se třemi prvky (1, 2 a 3). Pokud deserializujete JSON na tento typ, výchozí chování je, že hodnoty vlastností jsou nahrazeny:
- Pro
Numbers1, protože je jen pro čtení (bez setteru), má v seznamu stále hodnoty 1, 2 a 3. - Pro
Numbers2, který je pro čtení i zápis, je přidělen nový seznam a hodnoty z JSON se přidají.
Pokud například spustíte následující deserializační kód, Numbers1 obsahuje hodnoty 1, 2 a 3 a Numbers2 obsahuje hodnoty 4, 5 a 6.
A? a = JsonSerializer.Deserialize<A>("""{"Numbers1": [4,5,6], "Numbers2": [4,5,6]}""");
Chování při vyplňování
Počínaje rozhraním .NET 8 můžete změnit chování deserializace a upravit (naplnit) vlastnosti a pole namísto jejich nahrazení:
U vlastnosti typu kolekce se objekt znovu použije bez vymazání. Pokud je kolekce předem vyplněná prvky, zobrazí se v konečném deserializovaném výsledku spolu s hodnotami z JSON. Viz například příklad vlastnosti kolekce.
U vlastnosti, která je objektem s vlastnostmi, se jeho proměnlivé vlastnosti aktualizují na hodnoty JSON, ale samotný odkaz na objekt se nezmění.
U vlastnosti typu struktury je efektivní chování, že pro jeho proměnlivé vlastnosti jsou všechny existující hodnoty zachovány a přidány nové hodnoty z JSON. Na rozdíl od vlastnosti odkazu se však samotný objekt znovu nepoužívá, protože se jedná o typ hodnoty. Místo toho je změněna kopie struktury a potom znovu přiřazena k vlastnosti. Příklad viz Příklad vlastnosti Struktury.
Vlastnost struktury musí mít setter; InvalidOperationException jinak je vyvolán za běhu.
Poznámka:
Chování vyplnění v současné době nefunguje u typů, které mají parametrizovaný konstruktor. Další informace naleznete na issue dotnet/runtime 92877.
Vlastnosti pouze pro čtení
Pro naplnění proměnlivých vlastností odkazu, jelikož instance, na kterou tyto vlastnosti odkazují, není nahrazena, vlastnost nepotřebuje mít setter. Toto chování znamená, že deserializace může naplnit i vlastnosti jen pro čtení.
Poznámka:
Vlastnosti struktury stále vyžadují nastavovače, protože instance je nahrazena změněnou kopií.
Příklad vlastnosti kolekce
Vezměte v úvahu stejnou třídu A z příkladu chování nahrazení, ale tentokrát anotovanou s preferencí naplnění vlastností místo jejich nahrazení.
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
class A
{
public List<int> Numbers1 { get; } = [1, 2, 3];
public List<int> Numbers2 { get; set; } = [1, 2, 3];
}
Pokud spustíte následující deserializační kód, oba Numbers1 a Numbers2 obsahují hodnoty 1, 2, 3, 4, 5 a 6:
A? a = JsonSerializer.Deserialize<A>("""{"Numbers1": [4,5,6], "Numbers2": [4,5,6]}""");
Příklad vlastnosti Struktury
Následující třída obsahuje vlastnost struktury, S1jejíž deserializační chování je nastaveno na Populate. Po provedení tohoto kódu c.S1.Value1 má hodnotu 10 (z konstruktoru) a c.S1.Value2 má hodnotu 5 (z 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; }
}
Pokud se místo toho použilo výchozí Replace chování, c.S1.Value1 měla by po deserializaci výchozí hodnotu 0. To je proto, že konstruktor C() by byl volán, nastavil c.S1.Value1 na hodnotu 10, ale pak by byla hodnota S1 nahrazena novou instancí. (c.S1.Value2 bude stále 5, protože JSON nahradí výchozí hodnotu.)
Jak specifikovat
Existuje několik způsobů, jak určit volbu nahrazení nebo naplnění:
Pomocí atributu JsonObjectCreationHandlingAttribute můžete anotovat na úrovni typu nebo vlastnosti. Pokud nastavíte atribut na úrovni typu a nastavíte jeho Handling vlastnost na Populate, chování se použije pouze u těch vlastností, kde je možná populace (například typy hodnot musí mít setter).
Pokud chcete, aby Populatebyla předvolba pro celý typ , ale chcete vyloučit jednu nebo více vlastností z daného chování, můžete přidat atribut na úrovni typu a znovu na úrovni vlastnosti přepsat zděděné chování. Tento vzor je zobrazený v následujícím kódu.
// 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]; }Nastavte JsonSerializerOptions.PreferredObjectCreationHandling (nebo pro generování zdroje JsonSourceGenerationOptionsAttribute.PreferredObjectCreationHandling) a určete globální předvolbu.
var options = new JsonSerializerOptions { PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate };