???? Что такое Nullable reference type?
Nullable reference type
явным образом указывает, должна ли переменная содержать значение или может отсутсвовать.
Ключевые особенности
Design time анализ
Четкие контракты API
Поиск потенциальных мест
NullReferenceException
с помощью подсказок IDE
???? Рекомендуемые требования
.NET Standard 2.1+
Unity 2021+
???? Как включить статический анализ
Для анализа отдельных сборок
Создаем файл csc.rsp
рядом со сборкой asmdef
:
В содержимое csc.rsp
добавляем аргумент nullable
:
-nullable:enable
Для анализа отдельных .cs файлов
В содержимое .cs
добавляем контекст аннотаций #nullable
:
#nullable enable
namespace Sandbox.Domain
{
public struct User
{
public int Id { get; set; }
public string Nickname { get; set; }
public string? Phone { get; set; }
}
}
Теперь использую Nullable
тип, мы явно указываем что свойство Phone
может отсутствовать.
???? Руководство по миграции
Что делать с биндами Unity UI и DI Inject атрибутами?
Следует явно сообщить анализатору, что мы сами гаранитруем присвоение, подавив предупреждения c помощью null-forgiving оператора !
.
Пример с Unity UI:
[SerializeField] private Image _image = null!;
Пример с DI VContainer:
namespace Sandbox.Domain
{
private MoveController _moveController = null!;
[Inject]
public void Init(MoveController moveController)
{
_moveController = moveController;
}
}
Чтобы исключить из анализа отдельную часть кода, можно воспользоваться следующей аннотацией:
#nullable disable
using System;
namespace Sandbox.Server.Responses
{
[Serializable]
public class UserResponse
{
public int Id;
public string Name;
}
}
???? Полезные ссылки
Nullable reference types in Unity
NullReferenceException = ♥
Microsoft guide
Комментарии (5)
dreamcodestudio Автор
12.01.2024 18:01конкретно по 2 пункту, field-property
Стандартный UnityJsonUtility
не умел сериализовать свойства и при вызове методаJsonUtility.ToJson
результатом был пустой json.
Отпишите, если вдруг в какой-то версиях это добавили,
данный формат в Unity поддерживала только зависимость наNewtonsoft.Json
dreamcodestudio Автор
12.01.2024 18:01в случае использования
JsonUtility
через свойства с[field: SerializeField]
,
получится json c backing fields вида:{<Id>"k__BackingField":30518,<Name>"k__BackingField":"mesh"}
что явно может ломать backend, если на нем не используется явнай парсер от Unity
Newtonsoft.Json же при сериализации property, имеет стандартный формат вида:{"Id":30518,"Name":"mesh"}
rmolotov
Сразу вопрос: зачем нам nullable-типы в проекте, что мы хотим получить? В статье мотивация не раскрыта, обозначу сам -- чтобы получать предупреждение в редакторе о потенциальных NRE в коде.
Для этого существует Rider и аннотации, в частности [CanBeNull]. А здесь автор предлагает каждый класс пачкать директивой, так еще и по всему коду сборки бегать расставлять обратный костыль-директиву, в случае сборок разумеется.
Отдельно отмечу что единственный профит от сборок (AssemblyDefenition) - ускорение перекомпиляции скриптов проекта. Когда их добавляют на геймплейные модули и системы - больше проблем от распутывания референсов, чем выигрыша от реюза кода. Все примеры обожания асм-дефов которые я наблюдал начинались из-за неадекватно большого желания сэкономить время (= жадности) и/или большой глупости и заканчивались плачевно для проекта. Проекты были ГК и матч3, с попыткой выделения SDK и "собственного" фреймворка, чтоб конвеерно шлёпать прототипы. Конец немного предсказуем. В больших и хардкорных проектах такого недуга не наблюдал. Поэтому asmdef-ы использую только для того кода, который никогда не меняется -- сторонние библиотеки и фреймворки (если еще не) и базовые UI-компоненты (окна/кнопки для префабов, кладу в отдельную папку и сборку).
Отдельно поворчу, что:
1. Неизменяемые данные лучше делать
struct
или хотя быrecord
. Судя по[Serializable]
,UserResponse
- это все таки данные, одноразовые, зачем ониclass
?2. Их открытые члены -- свойствами, а не полями. Есть еще атрибут
[field:]
, если вдруг для Инспектора захочется не городить свойства+поля.3. Пул также совершенно зря наследуется от
MonoBehaviour
. Монобехи это бридж между C#-классами сервисов и миром Unity - объектами сцены. Не могу представить какие ссылки со сцены нужны пулу, ну если он только не спавнер одновременно.dreamcodestudio Автор
Cпс, за комменты
по поводу мотивиции, как раз указанн в самом вверху статьи 'Ключевые особенности' -
Поиск потенциальных мест с
NullReference
c 1-3 согласен, но данной контекс лишь изолированный пример, он служит только для показа nullable аннотаций
dreamcodestudio Автор
по поводу обмазывания аннотация никто это делать не предлагает, это лишь примеры как включить статический анализ в конкретных местах,
никто не запрещает сделать один глобальный конфиг nullable или все доменную область Game.asmdef отметить данной аннотацией
для этого их и сделали необязательным, чтобы можно было потихоньку включить анализ лишь для отдельных частей,
в конретной практике скажу, что это удобно даже больше для UPM packages, где юзер получает внешнее API и ему явно указывается контракт
Для меня это просто банально выглядиь читаемый, чем подстановки [CanBeNull] аттрибуты, особенно в случае с сигнатурами.
Это стоит воспринимать как еще один помощник статическу анализаторому, а не панацею от всех бед, т.к даже в офф. гите MS, можно найти довольно уникальный кейсы когда анализатор даже не заметит NullRef, т.к с новыми версиями .Net они дорабатывают ее.