Почему оператор возвращает 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 глубоко внутри).

Итог: если вы попытаетесь описать довольно продвинутую логику одним словом, у вас обязательно будет несколько человек смущен, так или иначе. Кажется, что большинство людей согласилось на один смысл, а те, кто не согласился, должны были приспособиться.