Почему оператор is возвращает false, если ему присвоено значение null?


135

Мне кажется, что isоператор немного противоречив.

bool Test()
{
    // Returns false, but should return true.
    return null is string;
}

Можно ожидать, что nullзначение принадлежит любому ссылочному (или обнуляемому) типу. И действительно, спецификация языка C # говорит что-то, что поддерживает эту гипотезу, например (6.1.6 Неявные ссылочные преобразования):

Неявные преобразования ссылок:
...
• Из литерала null в любой тип ссылки.

Описание (7.10.10 является оператором) из isначала оператора, говоря , что выражение (E is T)приведет верно , когда ссылочное преобразование из Eк Tсуществует, но затем авторы переходят явным исключением случая , когда Eэто nullбуквальным или имеет nullзначение ,

Почему они это делают? Мне это кажется нелогичным.


Почему они явно исключили нуль - в лучшем случае вопрос для programmers.stackoverflow.com
— Miserable Variable

2
Я не могу отменить свое закрытое
— Мерлин Морган-Грэм,

в Java null typeof Objectтакже возвращается false
— храповик урод

Предположим, что null is stringбыли true, и это подразумевало, что nullэто string. Также предположим, что null is Nullable<int>это trueозначает, что nullэто Nullable<int>. Теперь ответьте на этот вопрос: какого типа null?
— CVn

1
@ Майкл Кьёрлинг: не секвестр. Из упомянутых фактов (ноль - строка, нуль - Nullable <int>) не следует, что я должен быть в состоянии ответить на этот вопрос.
— Гебб

Ответы:


195

Этот вопрос был предметом моего блога 30 мая 2013 года . Спасибо за отличный вопрос!


Ты смотришь на пустую дорогу.

Кто-то спрашивает вас "может ли ваша дорога содержать Honda Civic?"

Да. Да, оно может.

Кто-то указывает вам на вторую дорогу. Это также пусто. Они спрашивают "Может ли текущее содержимое моей дороги вписаться в вашу дорогу?"

Да, очевидно. Обе дороги пусты! Так ясно, что содержимое одного может вписаться в другое, потому что в первую очередь нет содержимого ни того, ни другого.

Кто-то спрашивает вас "Есть ли на вашей дороге Honda Civic?"

Нет.

Вы думаете, что isоператор отвечает на второй вопрос: с учетом этого значения оно вписывается в переменную этого типа? Подходит ли нулевая ссылка в переменную этого типа? Да, это так.

Это не тот вопрос, на который isоператор отвечает. Вопрос, на который isоператор отвечает, является третьим вопросом. y is Xне спрашивает « является yдопустимым значением переменной типа X? », он спрашивает « Является yли допустимая ссылка на объект типа X? » Поскольку нулевая ссылка не является допустимой ссылкой на какой-либо объект любого типа, ответ «нет» ». Эта дорога пуста; это не содержит Honda Civic.

Другой способ взглянуть на это - это y is Xответить на вопрос «если бы я сказал y as X, получу ли я ненулевой результат? Если у ноль, ясно, что ответ - нет!


Чтобы взглянуть немного глубже на ваш вопрос:

Ожидается, что нулевое значение принадлежит любому ссылочному (или обнуляемому) типу

Можно было бы неявно предположить, что тип является набором значений , и что совместимость присваивания значения y с переменной типа X есть не что иное, как проверка того, является ли y членом множества x .

Хотя это чрезвычайно распространенный способ просмотра типов, это не единственный способ просмотра типов, и это не то, как C # смотрит на типы. Пустые ссылки не являются членами типа в C #; Совместимость присваивания - это не просто проверка набора на наличие значения. То, что нулевая ссылка является присваиванием, совместимым с переменной ссылочного типа X, не означает, что null является членом типа X. Отношение «совместимо с присваиванием» с отношением, а отношение «является членом типа», очевидно, имеет много перекрываются, но они не идентичны в CLR.

Если вас интересуют размышления о теории типов, посмотрите мои последние статьи на эту тему:

Что это за вещь, которую вы называете «типом»? Первая часть

Что это за вещь, которую вы называете «типом»? Часть вторая


@Gebb: рад помочь. Эта статья также может быть вам интересна: blogs.msdn.com/b/ericlippert/archive/2010/09/16/…
— Эрик Липперт,

Эрик превратил это в сообщение в блоге: ericlippert.com/2013/05/30/what-the-meaning-of-is-is
— Кевин Кэткарт

y is Xне спрашивает " yэто допустимое значение переменной типа X?" Он спрашивает "Является yли действительная ссылка на объект типа X?" Вот и весь смысл! Спасибо!
— Джалал

Но если я спрошу y is int?, то я буду спрашивать "Есть ли на вашей дороге Honda Civic или ничего?" Почему ответ все еще нет, когда ваша дорога пуста? Если вы заглянете под капот, то станет только хуже, поскольку возникает вопрос: «Есть ли на вашей дороге Honda Civic или табличка с надписью« Здесь нет Honda Civic »?». Даже если ваша подъездная дорога содержит указанный знак, ответ по-прежнему нет.
— Факс

1
@Gerard: Когда я даю длинные, подробные, болтливые ответы, люди говорят мне, что они должны быть короче, а когда я даю лаконичные, лаконичные ответы, люди говорят мне, что они должны быть длиннее. Мой вывод таков: людям нравится жаловаться. Поскольку у вас есть чувства по поводу того, что является хорошим ответом на этот восьмилетний вопрос, я предлагаю вам показать нам, что дает хороший ответ, ответив на него самостоятельно, чтобы мы могли учиться.
— Эрик Липперт

24

Я думаю, что null is stringвозвращать ложь очень интуитивно понятно. Нуль ничего не значит, и это определенно не строка. Так что должно возвращаться false. Хотя это выбор, который сделали дизайнеры языка, он очень интуитивен, если принять во внимание значение null в реальном мире.


2
+1, потому что вопрос действительно в том, интуитивен ли он, а не ставит ли вопрос спецификацию, о которой ОП уже знает. Если вы спросите его как английское предложение "is nulla string", ответ будет отрицательным, это не так, что отличается от "is nullassignable to string"
— Davy8

null is stringявляется довольно интуитивным, (string)null is stringможет потребовать паузу, если вы не очень хорошо знаете, как работает нулевая ссылка в C #.
— DecPL

24

nullБуквальный может быть назначен любой ссылочный тип. Это не прообраз сам по себе. Это специальный литерал, который представляет собой нулевую ссылку.

В случае, isесли он вернется, trueкогда nullбудет передано a , что вы сможете сделать с nullлитералом? Ничего - это так null. Какой смысл возвращаться, trueесли не считать запутанных вопросов?


Независимо от того, насколько это интуитивно понятно, прочитайте код на английском и скажите мне:

null is string;

Когда я вижу это, кажется, что задаю вопрос is "nothing" a string?. Моя интуиция говорит мне, что нет, это не так nothing.


Это нормально, но тогда это тоже строка, верно? Но почему тогда (null is string)возвращается вспышка?
— Гебб

Я бы сформулировал это наоборот. Любой тип ссылки может быть нулевым. ноль просто ноль.
— Марк Х

@Oded, так является ли нулевое значение допустимым значением, скажем, типа объекта? Я могу назначить его переменной этого типа, верно? Таким образом, ответ, кажется, да, значение совершенно правильно, и я предполагаю, что (null is object)выражение должно проверять именно это.
— Гебб

@Gebb: не забывайте, что ValueTypes также являются объектами, но не ссылочными типами.
— Марк Н

1
@Oded: "Какой смысл возвращать истину, если не путать?" На самом деле, это сделало бы язык более логичным. Рассмотрим эти два момента: (1) isоператор проверяет, существует ли ссылка (нам здесь не нужны другие типы преобразования); (2) nullможет быть преобразован в любой тип ссылки. Поэтому (null is T), где T является ссылочным типом, должен возвращать true. Но нет, здесь у нас есть это явное исключение, которое меня смущает.
— Гебб

12

http://msdn.microsoft.com/en-us/library/scekt9xw%28v=vs.71%29.aspx

Выражение is принимает значение true, если выполняются оба следующих условия:

  • выражение не является нулевым.
  • выражение может быть приведено к типу. Таким образом, приведенное выражение формы (тип (выражение) завершится без исключения. Для получения дополнительной информации см. 7.6.6. Приведенные выражения.

1
В любом случае, в документации только утверждается, что выражение не может быть нулевым (что мы уже знаем), но не объясняет почему
— имя пользователя

Почему вы хотите это по-другому?
— Мизерная переменная

1
@username: Этот ответ объясняет, как он работает механически, и приводит ссылку, которая дает вам модель для работы. Вы спрашиваете значение вселенной здесь. Полагаю, вам повезло, что наш бог часто бывает ТАК;)
— Мерлин Морган-Грэм,

10

На практике, имея «null is T == false», я могу сэкономить, набрав дополнительный код:

Вместо того, чтобы сказать

if (X != null && X is Foo) {}

Я могу просто сказать

if (X is Foo) {}

и покончим с этим.


8

nullзначение

Я процитировал это из твоего вопроса, потому что, похоже, он суть дела. null это не значение - это отсутствие значения. isМне кажется, что цель состоит в том, чтобы ответить на вопрос:

Если я бросаю Eк T, я буду успешно получить T?

Теперь, когда вы можете привести nullк T ошибке без ошибок , после этого у вас нет «у вас T» - у вас все еще ничего нет. Так что это не тот случай, когда null"is" a T, поэтому isвозвращает false.


3

В Java есть оператор , который делает то же самое, но он имеет гораздо более длинное название: instanceof. Там очень интуитивно понятно, что null instanceof Stringвозвращает false, потому что null не является экземпляром чего-либо, а тем более a String. Таким образом, при использовании nullверсии Java немного более интуитивно понятен.

Однако оба этих оператора возвращают true, когда их просят просмотреть всю иерархию. Например. если экземпляр Stringявляется Object. А вот это Java , что - х бит менее интуитивное (поскольку экземпляр на самом деле имеет один, очень специфический тип) и С # isболее интуитивно (потому что каждый String являетсяObject глубоко внутри).

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.