Обратите внимание, что для звонка на Console.WriteLine()
нет никаких причин. Свойство ссылочного типа не может иметь тип NULL, поэтому компилятору не нужно предупреждать, что оно может быть нулевым.
Вы можете утверждать, что компилятор должен предупреждать о ссылке в самом struct
. Это казалось бы разумным для меня. Но это не так. Похоже, это лазейка, вызванная инициализацией по умолчанию для типов значений, то есть всегда должен быть конструктор по умолчанию (без параметров), который всегда просто обнуляет все поля (нули для полей ссылочного типа, нули для числовых типов и т. Д.). ).
Я называю это лазейкой, потому что теоретически необнуляемые эталонные значения должны фактически быть ненулевыми! Duh. :)
Эта лазейка, по-видимому, решается в этой статье блога: Представление ссылочных типов, допускающих обнуляемость, в C #
Избегание нулей До сих пор предупреждения касались защитыnull в обнуляемых ссылках от разыменования. Другая сторона медали состоит в том, чтобы вообще не иметь нулевых значений в ненулевых ссылках.
Есть несколько способов, которыми могут возникнуть нулевые значения, и большинство из них стоит предупредить, в то время как параони вызовут еще одно «море предупреждений», которого лучше избегать:…
- Использование конструктора по умолчанию для структуры, которая имеет поле ненулевого ссылочного типа. Это подлый, так как конструктор по умолчанию (который обнуляет структуру) может даже неявно использоваться во многих местах. Вероятно, лучше не предупреждать [выделение шахты - PD] , иначе многие существующие типы структур станут бесполезными.
Другими словамиДа, это лазейка, но нет, это не ошибка. Разработчики языка знают об этом, но предпочли исключить этот сценарий из предупреждений, потому что иначе было бы нецелесообразно, учитывая, как работает struct
инициализация.
Обратите внимание, что это также соответствуетболее широкая философия за особенностью. Из той же статьи:
Итак, мы хотим, чтобы он жаловался на ваш существующий код. Но не противно. Вот как мы собираемся попытаться достичь этого баланса:...
Гарантированной нулевой безопасности не существует [выделено мной - PD] , даже если вы отреагируете и устраните все предупреждения. В анализе есть много пробелов по необходимости, а также по выбору.
К этому последнему пункту: иногда предупреждение является «правильным», но оно срабатывает все время на существующихкод, даже когда он на самом деле написан нулевым безопасным способом. В таких случаях мы будем ошибаться с точки зрения удобства, а не правильности. Мы не можем создавать «море предупреждений» в существующем коде: слишком много людей просто отключили бы предупреждения и никогда не извлекли бы из них пользу.
Также обратите внимание, что такая же проблема существует с массивами номинальнонеобнуляемые ссылочные типы (например, string[]
). При создании массива все ссылочные значения равны null
, и все же это допустимо и не будет выдавать никаких предупреждений.
Так много для объяснения, почему вещи такие, какие есть. Тогда возникает вопрос, что с этим делать? Это намного более субъективно, и я не думаю, что есть правильный или неправильный ответ. Тем не менее ...
Я лично буду относиться к своим struct
типам в каждом конкретном случае. Для тех, где intent на самом деле является обнуляемым ссылочным типом, я бы применил аннотацию ?
. Иначе я бы не стал.
Техникаlly, каждое значение ссылки в struct
должно быть «обнуляемым», то есть включать аннотацию ?
с именем типа. Но, как и во многих аналогичных функциях (например, async / await в C # или const
в C ++), это имеет «заразительный» аспект, в котором вам нужно будет либо переопределить эту аннотацию позже (с аннотацией !
),или включите явную проверку нуля, или только когда-либо присвойте это значение другой переменной типа ссылочного значения, допускающей значение nullable.
Для меня это во многом лишает цели включения ссылочных типов, допускающих значение null. Поскольку для таких членов типов struct
в любом случае потребуется обработка в специальном случае в любом случае, и поскольку единственный способ действительно безопасно обрабатывать его, при этом все еще имея возможность использовать ненулевые ссылочные типы, состоит в установке нуляпроверяет везде, где вы используете struct
, я чувствую, что разумным вариантом реализации является принятие того, что когда код инициализирует struct
, именно код должен сделать это правильно и убедиться, что элемент ненулевого ссылочного типа действительноинициализируется ненулевым значением.
Этому можно помочь, предоставив «официальные» средства инициализации, такие как конструктор не по умолчанию (т. е. конструктор с параметрами) или фабричный метод. Тем не менее всегда будет риск использования конструктора по умолчанию или его отсутствия вообще (как при выделении массива), но, предоставляя удобные средства для правильной инициализации struct
, это будет стимулировать код, использующий его, чтобы избежать нулевых ссылокв ненулевых переменных.
Тем не менее, если вы хотите 100% -ную безопасность по отношению к обнуляемым ссылочным типам, то ясно, что правильный подход для этой конкретной цели - всегда аннотировать каждый элемент ссылочного типа в struct
с ?
. Это означает каждое поле и каждое автоматически реализуемое свойство, а также любой метод или метод получения свойства, которые напрямую возвращают такие значения или произведение таких значений. Тогда потребляющий код должен будет включать проверки на нуль или оператор прощения на ноль в каждой точке, где такие значения копируются в ненулевые переменные.