#c# #nullable-reference-types
#c# #nullable-ссылочные типы
Вопрос:
.Net Core определяет object.ToString()
как public virtual string? ToString();
Это означает, что код, подобный следующему, вызывает CS8602
предупреждение «Разыменование ссылки, возможно, нулевой»:
object t = "test";
var s = t.ToString();
Console.WriteLine(s.Length); // Warning CS8602
Это легко исправить, написав s!.Length
или t.ToString()!;
, но мой вопрос:
При каких обстоятельствах было бы правильным возвращаться null
из реализации object.ToString()
?
Ответ, по-видимому, таков: «Вы никогда не должны возвращать значение null из object.toString ()», что достаточно справедливо, но это вызывает другой вопрос: «в таком случае, почему Microsoft объявила это как public virtual string? ToString();
«?
В сторону:
Некоторые комментарии ниже предполагают, что, поскольку реализация может неправильно возвращать значение null, возвращаемое значение должно быть объявлено как string?
.
Если это было правдой, то почему та же логика не применяется к ICloneable.Clone()
, который не объявлен как возвращаемый object?
?
И, конечно же, эта логика применима к каждому отдельному интерфейсному методу, который возвращает ссылочный тип? Любая реализация такого метода (например, ICustomFormatter.Format()
) теоретически может возвращать null
— и, следовательно, возвращаемое значение должно быть обнуляемым. Но это не так.
Прочитав ссылку, предоставленную DavidG, я полагаю, что обсуждение в этой теме отвечает на вопрос к моему удовлетворению:
Комментарии:
1. «При каких обстоятельствах было бы правильным возвращать значение null из реализации object. toString()?» Никогда, но возможно, что вы это сделаете.
2. Я не думаю, что для этого есть приемлемые обстоятельства, но поскольку «string» имеет значение null, и любой может написать свою собственную реализацию toString для своего объекта… Это все еще возможно…
3. Раздел примечаний буквально говорит вам не возвращать значение null. Я понятия не имею, почему это объявлено
string?
.4. Здесь есть некоторые обсуждения по этому поводу
5. Интересная цитата из Стивена Тоуба: «К вашему сведению, у нас есть API в .NET Core, которые возвращают null из toString»
Ответ №1:
Я не вижу причины, по которой кто-то хотел anything.ToString()
бы когда-либо вернуться null
, но кто знает?
Тогда, я думаю object.ToString()
, определяется как возвращающий a string?
по соображениям совместимости: это существует с версии v1 .NET и всегда определялось как возвращающий a string
, а a string
, являющийся ссылочным типом, может быть null. В «современном» объявлении просто указано, что: существует вероятность, что возвращаемая строка может быть нулевой.
И помните, что эта string?
вещь является очень недавней и просто метаданными: даже если она была введена string
(как это было в более старых версиях), реализации все равно могут возвращать значение null.
Другими словами, совершенно новые API могут (и должны) использовать аннотации с нулевым значением, как они хотят, но повторный ввод существующих библиотек должен учитывать то, что сделали библиотеки.
Я говорю повторный ввод, потому что на самом деле это не ввод текста, а просто аннотации, указывающие ожидаемое поведение. Это похоже на то, как Typescript «аннотирует» код Javascript: базовая система типов все еще старая.
Комментарии:
1. Итак, по этой логике, почему это не
ICloneable.Clone()
определяется какpublic object? Clone();
? Это не так — это определяется какpublic object Clone();
2. @MatthewWatson: Я не сотрудник Microsoft, поэтому я могу только догадываться, но мое предположение заключается в следующем: контракт для
IClonable.Clone()
всегда был «Создает новый объект, который является копией текущего экземпляра.» , что подразумевает, что возвращаемое значение не равно нулю, потому что новый объект никогда null (даже если не было поддержки компилятора для обеспечения этого во времена C # 1.0). Контракт дляobject.ToString()
just гласит: «Возвращает строку, представляющую текущий объект.» , что является менее строгим.3. @Heinzi Ну, null не является строкой (null не имеет никакого типа), поэтому я думаю, что «возвращает строку» означает, что она не должна возвращать значение null. И если вы посмотрите документацию для
object.ToString()
для ВСЕХ версий .Net, в ней говоритсяYour ToString() override should not return Empty or a null string.
4. @MatthewWatson: Я понимаю вашу точку зрения. Теперь я мог бы утверждать, что «должен» — это всего лишь рекомендация (и что фраза «нулевая строка» подразумевает, что null действительно считается допустимым значением для строки), но я предполагаю, что это было бы непросто, когда реальной причиной, вероятно, является прагматизм: есть много известных случаев, когда
object.ToString()
возвращаетnull, тогда как известно мало (если вообще есть) случаев, когдаICloneable.Clone()
возвращает null.5. Поскольку обсуждение в github.com/dotnet/coreclr/pull/23466 демонстрирует, что эти вопросы также обсуждались внутри Microsoft, пункт, который было рекомендовано реализовать
ToString
как возвращающий ненулевую строку, действительно был вызван pro-string?
. Я полагаю, что эти случаи обсуждались в каждом конкретном случае, чтобы сбалансировать совместимость с наилучшей практикой… Также обратите внимание, чтоobject.ToString()
возвратstring?
не препятствует возврату переопределенийstring
(об этом я узнал в том же выпуске GitHub).