Rispettare le annotazioni nullable
A partire da .NET 9, JsonSerializer include (limitato) supporto per l'imposizione dei tipi di riferimento non nullable sia nella serializzazione che nella deserializzazione. È possibile attivare o disattivare questo supporto usando il JsonSerializerOptions.RespectNullableAnnotations flag .
Ad esempio, il frammento di codice seguente genera un'eccezione JsonException durante la serializzazione con un messaggio simile al seguente:
La proprietà o il campo 'Name' nel tipo 'Person' non consente di ottenere valori Null. Prendere in considerazione l'aggiornamento dell'annotazione relativa ai valori Null.
public static void RunIt()
{
#nullable enable
JsonSerializerOptions options = new()
{
RespectNullableAnnotations = true
};
Person invalidValue = new(Name: null!);
JsonSerializer.Serialize(invalidValue, options);
}
record Person(string Name);
Analogamente, RespectNullableAnnotations applica nullbility alla deserializzazione. Il frammento di codice seguente genera un'eccezione JsonException durante la serializzazione con un messaggio simile al seguente:
Il parametro del costruttore 'Name' nel tipo 'Person' non consente valori Null. Prendere in considerazione l'aggiornamento dell'annotazione relativa ai valori Null.
public static void RunIt()
{
#nullable enable
JsonSerializerOptions options = new()
{
RespectNullableAnnotations = true
};
string json = """{"Name":null}""";
JsonSerializer.Deserialize<Person>(json, options);
}
record Person(string Name);
Suggerimento
- È possibile configurare il supporto dei valori Null a livello di singola proprietà usando le IsGetNullable proprietà e IsSetNullable .
- Il compilatore C# usa gli
[NotNull]
attributi ,[AllowNull]
,[MaybeNull]
e[DisallowNull]
per ottimizzare le annotazioni nei getter e nei setter. Questi attributi vengono riconosciuti anche da questa System.Text.Json funzionalità. Per altre informazioni sugli attributi, vedere Attributi per l'analisi statica dello stato Null.
Limiti
A causa della modalità di implementazione dei tipi riferimento non nullable, questa funzionalità presenta alcune limitazioni importanti. Acquisire familiarità con queste limitazioni prima di attivare la funzionalità. La radice del problema è che il supporto del tipo di riferimento non ha alcuna rappresentazione di prima classe nel linguaggio intermedio (IL). Di conseguenza, le espressioni MyPoco
e MyPoco?
sono indistinguabili dal punto di vista della reflection in fase di esecuzione. Mentre il compilatore tenta di crearlo creando metadati dell'attributo (vedere sharplab.io esempio), questi metadati sono limitati a annotazioni membro non generiche con ambito a una definizione di tipo particolare. Questa limitazione è il motivo per cui il flag convalida solo le annotazioni di valori Null che sono presenti su proprietà, campi e parametri del costruttore non generici. System.Text.Json non supporta l'applicazione dei valori Null per:
- Tipi di primo livello o il tipo passato quando si effettua la prima
JsonSerializer.Deserialize()
chiamata oJsonSerializer.Serialize()
. - Tipi di elemento raccolta, ad esempio i
List<string>
tipi eList<string?>
sono indistinguishable. - Qualsiasi proprietà, campi o parametri del costruttore generici.
Se si vuole aggiungere l'imposizione dei valori Null in questi casi, modellare il tipo in modo che sia uno struct (poiché non ammettono valori Null) o creare un convertitore personalizzato che esegue l'override della relativa HandleNull proprietà su true
.
Cambio di funzionalità
È possibile attivare l'impostazione a livello globale usando l'opzione RespectNullableAnnotations
di System.Text.Json.Serialization.RespectNullableAnnotationsDefault
funzionalità. Aggiungere l'elemento MSBuild seguente al file di progetto (ad esempio, file con estensione csproj ):
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Text.Json.Serialization.RespectNullableAnnotationsDefault" Value="true" />
</ItemGroup>
L'API RespectNullableAnnotationsDefault
è stata implementata come flag di consenso esplicito in .NET 9 per evitare l'interruzione delle applicazioni esistenti. Se si sta scrivendo una nuova applicazione, è consigliabile abilitare questo flag nel codice.
Relazione tra parametri nullable e facoltativi
RespectNullableAnnotations non estende l'imposizione ai valori JSON non specificati, perché System.Text.Json considera le proprietà obbligatorie e non nullable come concetti ortogonali. Ad esempio, il frammento di codice seguente non genera un'eccezione durante la deserializzazione:
public static void RunIt()
{
JsonSerializerOptions options = new()
{
RespectNullableAnnotations = true
};
var result = JsonSerializer.Deserialize<MyPoco>("{}", options);
Console.WriteLine(result.Name is null); // True.
}
class MyPoco
{
public string Name { get; set; }
}
Questo comportamento deriva dal linguaggio C# stesso, in cui è possibile avere proprietà obbligatorie che sono nullable:
MyPoco poco = new() { Value = null }; // No compiler warnings.
class MyPoco
{
public required string? Value { get; set; }
}
Inoltre, è possibile avere proprietà facoltative che non sono nullable:
class MyPoco
{
public string Value { get; set; } = "default";
}
La stessa ortogonalità si applica ai parametri del costruttore:
record MyPoco(
string RequiredNonNullable,
string? RequiredNullable,
string OptionalNonNullable = "default",
string? OptionalNullable = "default"
);