Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Начиная с .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);
Совет
- Можно настроить нулевую допустимость на уровне отдельного свойства с помощью свойств 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 в этих случаях, смоделируйте ваш тип как struct (поскольку они не допускают 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"
);
Отсутствующие значения против значений NULL
Важно понимать различие между отсутствующими свойствами исвойствами JSON с явными null значениями при установке RespectNullableAnnotations. JavaScript отличается от undefined (отсутствующее свойство) и null (явное значение NULL). Однако .NET не имеет undefined концепции, поэтому оба варианта десериализируются в null .NET.
При десериализации, если RespectNullableAnnotations является true:
Явное значение NULL создает исключение для свойств, не допускающих значение NULL. Например,
{"Name":null}вызывает исключение при десериализации в свойствоstring Name, которое не допускает значения null.Отсутствующие свойства не вызывают исключения, даже для свойств, не допускающих значение NULL. Например,
{}исключение не вызывается при десериализации в ненулевоеstring Nameсвойство. Сериализатор не задает свойство, оставляя его по умолчанию из конструктора. Для неинициализированного ссылочного типа, не допускающего значение NULL, это приводит кnull, что вызывает предупреждение компилятором.В следующем коде показано, как отсутствующие свойства не вызывают исключение во время десериализации:
public static void RunIt() { #nullable enable JsonSerializerOptions options = new() { RespectNullableAnnotations = true }; // Missing property - does NOT throw an exception. string jsonMissing = """{}"""; var resultMissing = JsonSerializer.Deserialize<Person>(jsonMissing, options); Console.WriteLine(resultMissing.Name is null); // True. } record Person(string Name);
Эта разница в поведении возникает, так как отсутствующие свойства обрабатываются как необязательные (не предоставленные), а явные null значения обрабатываются как предоставленные значения, которые нарушают ограничение, не допускающее значение NULL. Если необходимо обеспечить наличие свойства в JSON, используйте модификатор required или настройте свойство как обязательное с помощью JsonRequiredAttribute или модели контрактов.