День 1500. #ЗаметкиНаПолях
Избавляемся от Предупреждений Nullable-Типов в Объектах JSON
Использование обнуляемых ссылочных типов поможет вам избежать неприятных ошибок, а IDE сообщит вам о местах потенциальных проблем. Но как их использовать в типах, которые десериализуются из JSON?
Проблема в следующем: в проекте обычно есть несколько объектов передачи данных (DTO) или обычных объектов (POCO), которые объявляют свойства для десериализации данных. Вы точно знаете, что данные будут там после десериализации, поэтому объявляете свойства необнуляемыми. Тем не менее, компилятор (и IDE) настаивают на том, чтобы вы либо сделали свойство обнуляемым, либо инициализировали его. Есть несколько вариантов исправить это, каждый со своими преимуществами и нюансами.
1. Сделать свойство обнуляемым
public class User
{
[JsonProperty("name")]
public string? Name { get; set; }
}
Это уберёт предупреждение, но теперь придётся везде проверять свойство Name на null. Если вы точно знаете, что свойство всегда будет иметь значение, это добавляет много накладных расходов в вашу кодовую базу.
2. Добавить значение default! (пожалуйста, не надо)
Вы можете инициализировать свойство значением default!. Это фактически устанавливает значение в null, но подавляет предупреждение.
public string Name { get; set; } = default!;
Не делайте этого. Если десериализованный JSON не содержит значения свойства Name, теперь оно будет содержать null. Компилятор и IDE не будут предупреждать вас об этом, т.е. во время выполнения может быть выброшено неожиданное NullReferenceException.
Смысл обнуляемых ссылочных типов в том, чтобы предоставить вам систему безопасности, а это саботирует её. Подробнее про обнуляемый null можно почитать здесь.
3. Добавить первичный конструктор
Если вы используете Newtonsoft.Json, вы можете добавить в свой класс первичный конструктор, который устанавливает свойства. Десериализатор обнаружит это и вызовет конструктор вместо прямой установки свойств:
public class User
{
public User(string? name)
{
Name = name ?? "Unknown";
//или ArgumentNullException.ThrowIfNull(name)
}
[JsonProperty("name")]
public string Name { get; init; }
}
Предупреждение исчезнет, и ваш класс близок к JSON, который хотите десериализовать. Если вы уверены, что в JSON не будет null, имеет смысл использовать свойство, не допускающее null, и в C#.
Можно либо установить значение по умолчанию, либо выбрасывать ArgumentNullException в конструкторе. Последний вариант может означать исключение во время выполнения, но оно возникнет только тогда, когда что данные JSON не соответствуют вашим ожиданиям, и могут потребоваться другие действия (например, запись инцидента в лог) вместо того, чтобы просто продолжать выполнение кода.
4. Использовать required свойство
В C# 11 можно использовать модификатор required. В этом случае компилятор ожидает, что свойство всегда будет инициализировано и предупреждения не будет:
public required string Name { get; set; }
Такой подход чётко формулирует ожидания, не предоставляя компилятору и IDE ложной информации.
Имейте в виду, что модификатор required применяется во время компиляции, а не во время выполнения. Если JSON содержит null, нет никакой гарантии, что вы избежите NullReferenceException. В этом случае лучше использовать string? и выполнять проверки на null, где это применимо.
Источник: https://blog.maartenballiauw.be/post/2023/01/12/getting-rid-of-warnings-with-nullable-reference-types-and-json-object-models-in-csharp.html