Примечания, допускающие значение NULL
Начиная с .NET 9, JsonSerializer поддерживает (ограниченную) поддержку ненулевого ссылочного типа в сериализации и десериализации. Эту поддержку можно переключить с помощью флага JsonSerializerOptions.RespectNullableAnnotations .
Например, следующий фрагмент кода создает JsonException исключение во время сериализации с таким сообщением:
Свойство или поле "Имя" в типе "Person" не позволяет получать значения NULL. Рассмотрите возможность обновления заметки о допустимости 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);
Аналогичным образом RespectNullableAnnotations применяется возможность null при десериализации. Следующий фрагмент кода создает JsonException исключение во время сериализации с сообщением, например:
Параметр конструктора "Имя" типа "Person" не разрешает значения NULL. Рассмотрите возможность обновления заметки о допустимости 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);
Совет
- Можно настроить значение NULL на уровне отдельного свойства с помощью IsGetNullable свойств и IsSetNullable свойств.
- Компилятор C# использует
[NotNull]
атрибуты ,[AllowNull]
[MaybeNull]
а также[DisallowNull]
атрибуты для точной настройки заметок в методах получения и заданиях. Эти атрибуты также распознаются этой System.Text.Json функцией. (Дополнительные сведения об атрибутах см. в разделе Атрибуты для статического анализа состояния NULL.)
Ограничения
Благодаря реализации ссылочных типов, не допускающих значение NULL, эта функция имеет некоторые важные ограничения. Ознакомьтесь с этими ограничениями перед включением функции. Корень проблемы заключается в том, что ссылочный тип NULL не имеет представления первого класса на промежуточном языке (IL). Таким образом, выражения и MyPoco?
неразличимы MyPoco
с точки зрения отражения времени выполнения. Хотя компилятор пытается сделать это путем создания метаданных атрибутов (см . sharplab.io примере), эти метаданные ограничены заметками не универсальных элементов, которые относятся к определенному определению типа. Это ограничение является причиной того, что флаг проверяет только заметки nullability, которые присутствуют в не универсальных свойствах, полях и параметрах конструктора. System.Text.Json не поддерживает принудительное применение null в:
- Типы верхнего уровня или тип, передаваемый при выполнении первого
JsonSerializer.Deserialize()
илиJsonSerializer.Serialize()
вызова. - Типы элементов коллекции, например,
List<string>
иList<string?>
типы являются неотличимыми. - Все свойства, поля или параметры конструктора, которые являются универсальными.
Если вы хотите добавить принудительное применение null в этих случаях, либо моделируйте тип структуры (так как они не допускают значения NULL), либо создайте настраиваемый преобразователь, который переопределяет его HandleNull свойство true
.
Переключатели функции
Вы можете включить RespectNullableAnnotations
параметр глобально с помощью System.Text.Json.Serialization.RespectNullableAnnotationsDefault
переключателя функций. Добавьте следующий элемент MSBuild в файл проекта (например, CSPROJ-файл ):
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Text.Json.Serialization.RespectNullableAnnotationsDefault" Value="true" />
</ItemGroup>
RespectNullableAnnotationsDefault
API был реализован как флаг согласия в .NET 9, чтобы избежать нарушения существующих приложений. Если вы пишете новое приложение, настоятельно рекомендуется включить этот флаг в коде.
Связь между допустимыми значениями NULL и необязательными параметрами
RespectNullableAnnotations не расширяет принудительное применение к неуказаемым значениям JSON, так как System.Text.Json обрабатывает обязательные и ненулевое свойства как ортгональные понятия. Например, следующий фрагмент кода не создает исключение во время десериализации:
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; }
}
Это поведение связано с самим языком C#, где можно иметь необходимые свойства, допускающие значение NULL:
MyPoco poco = new() { Value = null }; // No compiler warnings.
class MyPoco
{
public required string? Value { get; set; }
}
Кроме того, можно иметь необязательные свойства, не допускающие значения NULL:
class MyPoco
{
public string Value { get; set; } = "default";
}
Та же ортогональность применяется к параметрам конструктора:
record MyPoco(
string RequiredNonNullable,
string? RequiredNullable,
string OptionalNonNullable = "default",
string? OptionalNullable = "default"
);