Почему оператор возвращает false при задании значения null?
Мне кажется, что оператор is
немного несогласован.
bool Test()
{
// Returns false, but should return true.
return null is string;
}
Ожидается, что значение null
принадлежит любому ссылочному (или нулевому) типу. И действительно, спецификация языка С# говорит то, что поддерживает эту гипотезу, например (6.1.6 Неявные ссылки):
Неявные ссылочные преобразования:
...
• От нулевого литерала до любого ссылочного типа.
Описание (7.10.10 Оператор is) оператора is
начинается тем, что выражение (E is T)
приведет к истине, когда существует ссылочное преобразование от E
до T
, но затем авторы продолжайте, явно исключая случай, когда E
является литералом null
или имеет значение null
.
Почему они это делают? Для меня это кажется противоречивым.
Ответы
Ответ 1
Этот вопрос был предметом
Да. Да, это возможно.
Кто-то указывает на вторую дорогу. Он также пуст. Они спрашивают: "Может ли текущее содержимое моей подъездной дороги вписаться в вашу дорогу?"
Да, очевидно. Оба подъезда пустые! Так ясно, что содержимое одного может поместиться в другое, потому что в нем нет ни того, ни другого.
Кто-то спрашивает вас: "У вашей дороги есть Honda Civic?"
Нет, это не так.
Вы думаете, что оператор is
отвечает на второй вопрос: учитывая это значение, соответствует ли он переменной этого типа? Нулевая ссылка вписывается в переменную этого типа? Да, да.
Это не вопрос, на который отвечает оператор is
. Вопрос, который отвечает оператор is
, является третьим вопросом. y is X
не спрашивает "есть y
юридическое значение переменной типа X
?" Он спрашивает: "Является ли y
действительной ссылкой на объект типа X
?" Поскольку нулевая ссылка не является действительной ссылкой на любой объект любого типа, ответ "нет". Эта подъездная дорога пуста; он не содержит Honda Civic.
Другой способ посмотреть, что y is X
отвечает на вопрос "если бы я сказал y as X
, мог бы получить ненулевой результат? Если y является нулевым, то, очевидно, ответ не равен!
Посмотрите немного глубже на свой вопрос:
Предполагается, что нулевое значение относится к любому ссылочному (или нулевому) типу
Можно было бы предположить, что тип - это набор значений, а совместимость присваивания значения y с переменной типа X - не что иное, как проверка того, является ли y членом множества x.
Хотя это очень распространенный способ просмотра типов, это не единственный способ взглянуть на типы, и это не так, как С# смотрит на типы. Нулевые ссылки не являются членами типа С#; совместимость присваивания - это не просто проверка набора, чтобы увидеть, содержит ли оно значение. Просто потому, что нулевая ссылка - это присвоение, совместимое с переменной ссылочного типа X, не означает, что значение null является членом типа X. Согласование "присваивание совместимо с" и отношение "является членом типа", очевидно, имеет много перекрываются, но они не идентичны в CLR.
Если размышления о теории типов вас интересуют, ознакомьтесь с моими недавними статьями по теме:
Ответ 2
Литерал null
может быть назначен любому ссылочному типу. Это не тип в себе. Это специальный литерал, который представляет нулевую ссылку.
В случае, если is
вернет true
, когда будет передан null
, что бы вы могли сделать с литералом null
? Ничего - это null
. Каким будет смысл в возвращении true
за исключением путающих вопросов?
Независимо от того, насколько интуитивно понятным, прочитайте код на английском языке и скажите мне:
null is string;
Когда я вижу это, кажется, задает вопрос is "nothing" a string?
. Моя интуиция говорит мне, что нет, это не так - это nothing
.
Ответ 3
Я думаю, что null is string
возврат false очень интуитивно. Нуль ничего не значит, и это определенно не строка. Поэтому он должен возвращать false. Хотя это выбор, сделанный разработчиками языка, он очень интуитивный, когда вы считаете значение реального мира нулевым.
Ответ 4
http://msdn.microsoft.com/en-us/library/scekt9xw%28v=vs.71%29.aspx
An выражение выражает true, если оба из следующих условий: выполняются:
- выражение не равно нулю.
- выражение может быть применено к типу. То есть, литое выражение form (type (выражение)) завершится без исключения исключения. Для получения дополнительной информации см. 7.6.6 Экспрессивные выражения.
Ответ 5
Как практический вопрос, имея "null is T == false", я могу набрать лишний код:
Вместо того, чтобы сказать
if (X != null && X is Foo) {}
Я могу просто сказать
if (X is Foo) {}
и выполняться с ним.
Ответ 6
значение null
Я процитировал это из вашего вопроса, потому что это, похоже, доходит до сути дела. null
не является значением - это отсутствие значения. Цель is
мне, похоже, ответить на вопрос:
Если я отбрасываю E
в T
, успешно ли получим T
?
Теперь, когда вы можете отбрасывать null
до T
без ошибок, после этого вы не имеете "T
" - у вас все равно ничего нет. Так что это не тот случай, когда null
"является" T
, поэтому is
возвращает false.
Ответ 7
В Java есть оператор, который выполняет точно такую же вещь, но имеет гораздо более длинное имя: instanceof
. Здесь очень интуитивно понятно, что null instanceof String
возвращает false, потому что null не является экземпляром чего-либо, а тем более a String
. Таким образом, при использовании null
версия Java более интуитивно понятна.
Однако оба этих оператора возвращают true, когда их просят также просмотреть всю иерархию. Например. если экземпляр String
является Object
. И здесь это Java, который немного менее интуитивно понятен (потому что у экземпляра действительно есть один, очень специфический тип), а С# is
более интуитивно понятен (потому что каждый String
a Object
глубоко внутри).
Итог: если вы попытаетесь описать довольно продвинутую логику одним словом, у вас обязательно будет несколько человек смущен, так или иначе. Кажется, что большинство людей согласилось на один смысл, а те, кто не согласился, должны были приспособиться.