Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
A partire da .NET 8, è possibile specificare una preferenza per sostituire o popolare le proprietà .NET quando JSON viene deserializzato. L'enumerazione JsonObjectCreationHandling fornisce le scelte di gestione della creazione di oggetti:
Comportamento predefinito (sostituzione)
Il System.Text.Json deserializzatore crea sempre una nuova istanza del tipo di destinazione. Tuttavia, anche se viene creata una nuova istanza, alcune proprietà e campi potrebbero essere già inizializzati come parte della costruzione dell'oggetto. Si consideri il tipo seguente:
class A
{
public List<int> Numbers1 { get; } = [1, 2, 3];
public List<int> Numbers2 { get; set; } = [1, 2, 3];
}
Quando si crea un'istanza di questa classe, il Numbers1 valore della proprietà (e Numbers2) è un elenco con tre elementi (1, 2 e 3). Se si deserializza JSON in questo tipo, il comportamento predefinito è che i valori delle proprietà vengono sostituiti:
- Per
Numbers1, poiché è di sola lettura (nessun setter), ha ancora i valori 1, 2 e 3 nell'elenco. - Per
Numbers2, che è di lettura e scrittura, viene allocata una nuova lista e vengono aggiunti i valori dal JSON.
Ad esempio, se si esegue il codice di deserializzazione seguente, Numbers1 contiene i valori 1, 2 e 3 e Numbers2 contiene i valori 4, 5 e 6.
A? a = JsonSerializer.Deserialize<A>("""{"Numbers1": [4,5,6], "Numbers2": [4,5,6]}""");
Comportamento di popolamento
A partire da .NET 8, è possibile modificare il comportamento di deserializzazione in modo da modificare (popolare) le proprietà e i campi anziché sostituirli:
Per una proprietà di tipo raccolta, l'oggetto viene riutilizzato senza svuotare. Se la raccolta è prepopolata con gli elementi, questi verranno visualizzati nel risultato deserializzato finale insieme ai valori del JSON. Per un esempio, vedere Esempio di proprietà Collection.
Per una proprietà che è un oggetto con proprietà, le relative proprietà modificabili vengono aggiornate ai valori JSON, ma il riferimento all'oggetto stesso non cambia.
Per una proprietà di tipo struct, il comportamento effettivo è che per le relative proprietà modificabili, tutti i valori esistenti vengono mantenuti e vengono aggiunti nuovi valori dal codice JSON. Tuttavia, a differenza di una proprietà di riferimento, l'oggetto stesso non viene riutilizzato perché è un tipo di valore. Invece, viene modificata una copia della struttura e quindi riassegnata alla proprietà. Per un esempio, vedere Esempio di proprietà Struct.
Una proprietà struct deve avere un setter; in caso contrario, viene generata un'eccezione InvalidOperationException in fase di esecuzione.
Annotazioni
Il comportamento di popolamento attualmente non funziona per i tipi con un costruttore con parametri. Per altre informazioni, vedere dotnet/runtime issue 92877.
Proprietà di sola lettura
Per popolare le proprietà di riferimento modificabili, poiché l'istanza a cui fa riferimento la proprietà non viene sostituita, la proprietà non deve avere un setter. Questo comportamento significa che la deserializzazione può anche popolare le proprietà di sola lettura .
Annotazioni
Le proprietà dello struct richiedono ancora setter perché l'istanza viene sostituita con una copia modificata.
Esempio di proprietà di collezione
Si consideri la stessa classe A dell'esempio di comportamento di sostituzione, ma questa volta annotata con una preferenza per riempire le proprietà anziché sostituirle:
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
class A
{
public List<int> Numbers1 { get; } = [1, 2, 3];
public List<int> Numbers2 { get; set; } = [1, 2, 3];
}
Se si esegue il codice di deserializzazione seguente, entrambi Numbers1 e Numbers2 contengono i valori 1, 2, 3, 4, 5 e 6:
A? a = JsonSerializer.Deserialize<A>("""{"Numbers1": [4,5,6], "Numbers2": [4,5,6]}""");
Esempio di proprietà Struct
La classe seguente contiene una proprietà struct, S1, il cui comportamento di deserializzazione è impostato su Populate. Dopo l'esecuzione di questo codice, c.S1.Value1 ha un valore pari a 10 (dal costruttore) e c.S1.Value2 ha un valore pari a 5 (dal codice 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; }
}
Se invece è stato usato il comportamento predefinito Replace , c.S1.Value1 avrà il valore predefinito 0 dopo la deserializzazione. Questo perché il costruttore C() viene chiamato, impostando c.S1.Value1 su 10, ma il valore di S1 verrà sostituito con una nuova istanza. (c.S1.Value2 sarebbe ancora 5, perché JSON sostituisce il valore predefinito.
Come specificare
Esistono diversi modi per specificare un'opzione per sostituire o popolare:
Usare l'attributo JsonObjectCreationHandlingAttribute per annotare a livello di tipo o proprietà. Se si imposta l'attributo a livello di tipo e si imposta la relativa Handling proprietà su Populate, il comportamento verrà applicato solo a tali proprietà in cui è possibile eseguire il popolamento( ad esempio, i tipi valore devono avere un setter).
Se si desidera che la preferenza a livello di tipo sia Populate, ma si desidera escludere una o più proprietà da tale comportamento, è possibile aggiungere l'attributo a livello di tipo e di nuovo a livello di proprietà per eseguire l'override del comportamento ereditato. Questo modello è illustrato nel codice seguente.
// 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]; }Impostare JsonSerializerOptions.PreferredObjectCreationHandling (o, per la generazione di origine, JsonSourceGenerationOptionsAttribute.PreferredObjectCreationHandling) per specificare una preferenza globale.
var options = new JsonSerializerOptions { PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate };