Чому оператор повертає значення false, коли йому задано null?


135

Мені здається, що isоператор трохи непослідовний.

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

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

Неявні перетворення посилань:
...
• Від нульового буквального до будь-якого типу посилань.

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

Чому вони роблять це? Мені це здається протизаконним.


Чому вони явно виключили null - це в кращому випадку питання для
programer.stackoverflow.com

2
Я не можу скасувати своє закрите
Мерлін Морган-Грем

в java null typeof Objectтакож повертається false
ratchet freak

Припустимо, що це null is stringбуло true, і це означало, що nullце а string. Припустимо також, що null is Nullable<int>це trueозначає, що nullце a Nullable<int>. Тепер дайте відповідь на це питання: що це за тип null?
CVn

1
@Michael Kjörling: Не послідовність. Зі згаданих фактів (null - рядок, null - 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 недійсний, однозначно відповідь - ні!"


Щоб трохи глибше подивитися на своє запитання:

Можна очікувати, що нульове значення належить до будь-якого еталонного (або нульового) типу

Можна неявно припустити, що тип - це набір значень , і сумісність присвоєння значення 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повернути помилкове дуже інтуїтивно. Null нічого не означає, і це точно не є рядком. Отже, він повинен повернути помилкове. Хоча це вибір, який зробили дизайнери мови, він дуже інтуїтивно зрозумілий, коли ви вважаєте значення реального світу нульовим.


2
+1, оскільки питання справді полягає в тому, чи є це інтуїтивно зрозумілим, а не сумнівом у специфікаціях, про які вже знає ОП. Якщо ви запитуєте це як англійське речення "є nullрядок", відповідь "ні", це не так, що відрізняється від " nullпризначається string"
Davy8

null is stringдосить інтуїтивно зрозумілий, (string)null is stringможе знадобитися пауза, якщо ви не дуже знайомі з тим, як працює нульова посилання на C #.
грудня

24

nullБуквальний може бути призначений будь-який контрольний тип. Він не є самим типом. Це особливий літерал, який представляє нульову посилання.

У випадку, який isби повернувся, trueколи nullбуло передано передачу, що б ви могли зробити з nullбуквальним? Нічого - воно є null. Який би сенс повернутись, trueокрім заплутаних питань?


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

null is string;

Коли я це бачу, то, здається, задаю питання is "nothing" a string?. Моя інтуїція підказує мені, що ні, це не так nothing.


Це нормально, але тоді це також струна, правда? Але навіщо (null is string)тоді повертати промінь?
Гебб

Я б це сформулював навпаки. Будь-який тип посилання може бути недійсним. null просто null.
Марк Н

@Oded, значить, нульове значення є дійсним значенням, скажімо, типу об’єкта? Я можу призначити його змінній цього типу, правда? Тож відповідь здається так, значення цілком вірно, і я гадаю, що (null is object)вираз повинен перевірити саме це.
Гебб

@Gebb: Не забувайте, що ValueTypes також є об'єктами, але не посиланнями.
Марк Н

1
@Oded: "Який би сенс повернути правду, крім заплутаних питань?" Власне, це зробило б мову більш логічною. Розглянемо ці два моменти: (1) isоператор перевіряє, чи існує посилання (тут нам не потрібні інші типи перетворення); (2) nullможе бути перетворений на будь-який тип посилання. Тому (null is T), де T є еталонним типом, слід повернути істину. Але ні, тут у нас є той явний виняток, який мені здається заплутаним.
Гебб

12

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

Вираз виражається як істинне, якщо виконуються обидві наступні умови:

  • вираз не є нульовим.
  • вираз може бути передано на тип. Тобто виразний вираз форми (тип (вираз) буде завершений, не викидаючи виняток. Для отримання додаткової інформації див. 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"є" а T, тому isповертається хибною.


3

У Java є оператор , який робить те ж саме, але він має набагато більше довгу назву: instanceof. Там дуже інтуїтивно null instanceof Stringповертається помилка, оскільки null не є примірником нічого, тим більше a String. Отже, при використанні nullверсії Java трохи інтуїтивніше.

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

Підсумок: якщо ви спробуєте одним словом описати досить вдосконалену логіку, ви, мабуть, мало людей плутаєте, так чи інакше. Схоже, більшість людей погодилися на одне значення, а тим, хто не погодився, довелося коригуватися.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.