Чому> = повертає false, якщо == повертає true для нульових значень?


78

У мене є дві змінні типу int? (або Nullable <int>, якщо хочете). Я хотів зробити порівняння двох змінних більшим, ніж чи рівним (> =), але, як виявляється, це повертає значення false, якщо обидві змінні є нульовими, тоді як, очевидно, оператор == повертає true.

Хтось може пояснити мені, чому це логічно, оскільки семантичне визначення оператора> = містить слово "або"?


1
Чи можете ви розмістити код, який створює цю дивну поведінку?
Android Eve

12
Насправді, я б поставив питання, чи доречно == повертати true. Я вважаю, що це зовсім не доречно. Як можна дві змінні, значення яких невідоме, засвідчити рівними?
Charles Bretana

2
@Charles, тому що, якщо вони мають той же обнуляється типу (наприклад int?), то їх вартість буде відома. null.
Moo-Juice

3
@ moo-juice, Не в моєму світі ... Якщо ваше ім'я нульове, чи можете ви відповісти на це? null - це не те саме, що "null". Є старий фільм під назвою «Мене звати ніхто» («Хто розбив скло, діти?» ---- «Ніхто») То хто такий «Ніхто»? У реальному світі (за межами внутрішніх елементів коду) null означає, що значення невідоме .... Значення структури даних може бути відоме (воно є Null), але сутність / значення реальної проблеми домену, яке змінна повинна представляти, це Невідомо ..
Charles Bretana

2
@ Чарльз, люблю аналогію !. Але хто не розбив скло?
Moo-Juice

Відповіді:


97

Були величезні суперечки щодо цього дивацтва, коли функція була спочатку розроблена ще в C # 2.0. Проблема в тому, що користувачі C # повністю звикли, що це має значення:

if(someReference == null)

Розширюючи рівність до типів значень, що допускають обнулення, у вас є наступний вибір.

  1. Nullable рівність дійсно піднімається . Якщо один або обидва операнди є нульовими, то результат не є ні true, ні false, але null. У цьому випадку ви можете:

    • а) Зробити незаконним наявність рівності типу значення, що допускає обнулення, в ifоператорі, оскільки для ifоператора потрібен bool, а не nullable bool. Натомість вимагайте від усіх, HasValueякщо вони хочуть порівняти з null. Це багатослівно і дратує.

    • б) Автоматично перетворювати null у false. Недоліком цього є те, що x==nullповертає false, якщо x має значення null, що заплутано і працює проти розуміння людьми нульових порівнянь із посилальними типами.

  2. Допустима рівність не може бути скасована. Нульова рівність є істинною чи помилковою, а порівняння з null - це нульова перевірка. Це робить нульову рівність суперечливою нерівній нерівності.

Жоден з цих варіантів, очевидно, не є правильним; всі вони мають плюси і мінуси. Наприклад, VBScript вибирає 1b. Після довгих дебатів команда дизайнерів C # обрала №2.


Як нульова рівність не відповідає нерівній нерівності у виборі No2?
MCS

3
@MCS: Точно таким чином, який спонукає питання в першу чергу. == може бути true, якщо <= false.
Ерік Ліпперт,

@Eric: Дякую - я думав, що "нерівність" стосується лише! =, Що насправді відповідає ==. Не зрозумів, що це математичний термін: en.wikipedia.org/wiki/Inequality_(mathematics) .
MCS

1
Ну, інше питання (який ви не зверталися), що робити , коли ви намагаєтеся зробити <, <=, =>або >коли один з операндів null. У C # відповідь - return false. У Stringкласі Scala / Java відповідь - кинути a NullPointerException.
Ken Bloom

3
@Brian: тоді навіщо взагалі дозволяти операторам типи, що допускають обнулення? Якщо вони завжди викидають нульове значення типу, що опускається, тоді ви можете просто визначити оператор лише для ненульованих типів і змусити користувача вставити перетворення в ненульований, оскільки це те, що їм доведеться зробити, щоб виключити виняток.
Eric Lippert,

60

Оскільки Рівність визначається окремо від Порівняльності.
Ви можете перевірити, x == nullале x > nullце безглуздо. У C # це завжди буде помилковим.


1
+1: ось посилання MSDN msdn.microsoft.com/en-us/library/2cf62fcy.aspx , але, на жаль, вони забули пояснити поведінку операторів порівняння у випадку 2 нулів (згадали лише рівність) ...
digEmAll

3
так, але оператор більше або дорівнює. Я бачу таблицю істинності, але я, як правило, погоджуюся з OP,> = більше або дорівнює, якщо null == null істинно, null> = null також повинно бути істинним. Я думаю, ми просто додаємо це до реалізації та зручності користувача, щоб зберегти перевірку == null.
BlackICE

2
@David, див. Відповідь Еріка: "Жоден з цих варіантів, очевидно, не правильний". Але загалом, коли тип рівноцінний, але не порівнянний, тоді >=просто не визначається.
Henk Holterman

11

Інший спосіб опису '> =': Не менше ніж. Жодної згадки про рівних. Як тільки одним із операндів у тесті на нерівність є Null, результат також невідомий (null). Однак якщо ви хочете дізнатися, чи обидва операнди мають значення Null, тоді Null == Null - це розумний тест (результат повинен бути істинним). Позбавлення від нерівності частини оператора має велике значення.

Наступний приклад коду з http://msdn.microsoft.com/en-us/library/2cf62fcy.aspx#sectionToggle4 узагальнює, як C # обробляє Null:

int? num1 = 10;   
int? num2 = null;   
if (num1 >= num2)   
{   
    Console.WriteLine("num1 is greater than or equal to num2");   
}   
else   
{   
    // This clause is selected, but num1 is not less than num2.   
    Console.WriteLine("num1 >= num2 returned false (but num1 < num2 also is false)");   
}   

if (num1 < num2)   
{   
    Console.WriteLine("num1 is less than num2");   
}   
else   
{   
    // The else clause is selected again, but num1 is not greater than   
    // or equal to num2.   
    Console.WriteLine("num1 < num2 returned false (but num1 >= num2 also is false)");   
}   

if (num1 != num2)   
{   
    // This comparison is true, num1 and num2 are not equal.   
    Console.WriteLine("Finally, num1 != num2 returns true!");   
}   

// Change the value of num1, so that both num1 and num2 are null.   
num1 = null;   
if (num1 == num2)   
{   
    // The equality comparison returns true when both operands are null.   
    Console.WriteLine("num1 == num2 returns true when the value of each is null");   
}   

/* Output:   
 * num1 >= num2 returned false (but num1 < num2 also is false)   
 * num1 < num2 returned false (but num1 >= num2 also is false)   
 * Finally, num1 != num2 returns true!   
 * num1 == num2 returns true when the value of each is null   
 */   

Це цікава ментальна модель. Однак Розділ § 1.4 специфікації C # називає цих операторів Меншими або Рівними та Більшими або рівними
Конрад Фрікс,

3
@Conrad Що якраз ілюструє проблеми перекладу мови програмування (в даному випадку C #) англійською мовою. ІМХО, коли Nulls фігурують у логіці, вам потрібно мати справу з результатом трьох станів (істинним, хибним, невідомим). Будь-який вираз, що включає Null, повинен призводити до невідомого, за винятком Null == xякого є явний тест на невідоме, що призводить до true або false.
NealB

@NealB: Насправді, специфікація стверджує, що> = і <= означають те, що ви очікуєте від них - розділ §7.10 чітко дає зрозуміти, що операція 'x op y' для <= і> = покликана дорівнювати - до або більше, ніж / менше, ніж можна було б очікувати.
nicodemus13

2

>=оперує числовим значенням; що нуль не є.

Ви можете перевантажити на >=оператор , щоб забезпечити те , що ви хочете від типу конкретного.


він оперує нульовими типами, повертає false
BlackICE

Він обробляє нульові типи так ... семантика того, що ми будемо визначати як "оперує". Оборонне кодування; це null, тоді виконайте x проти обробки null як буквального значення при прийнятті рішень під час оцінки.
Aaron McIver

Зазвичай не можна перевантажувати оператори, оскільки їх можна визначити лише всередині їх власних класів. Тож у цьому випадку вам знадобиться доступ до Nullable<T>коду.
ANeves вважає, що SE є злим

0

NULL - це не нуль (числове або двійкове значення), рядок нульової довжини або порожній (значення символу). Тож будь-який оператор порівняння завжди повертає на нього значення false. Детальніше про це читайте тут


8
База даних NULL - це не C # null. Крім того, оператори порівняння на типах C #, що допускають нуль, є дивним звіром, який не обов'язково дотримується звичайних правил для нульових порівнянь.
Йорен

3
Відповідь все-таки правильна, просто посилання неправильне. msdn.microsoft.com/en-us/library/2cf62fcy.aspx#sectionToggle4
unholysampler

5
@unholy: Відповідь неправильна, і що більш важливо, вона базується на неправильних аргументах.
Йорен

0

Яких цінностей ви б очікували?

null == null true

null> = null false

null> null false

null <= null false

null <null false

null! = нуль false

1 == null false

1> = null false

1> null false

1 <= null false

1 <null false

1! = Null true aka! (1 == null)


0

> = означає лише "більше або рівне", якщо воно використовується в цьому конкретному чітко визначеному вигляді. При використанні в класі з перевантаженими операторами це означає все, що розробник класу хоче, щоб це означало. Застосовуючись до рядкоподібного класу, це може означати "сортування однакове або вище", або може означати "однакової довжини або довше".


0

Оскільки за замовчуванням значення an intне може бути нульовим, і для його значення буде встановлено значення 0, оператор> і <, який побудований для intтипу, очікує працювати з, valuesа не з nulls.

див. мою відповідь на подібне запитання, де я написав кілька способів роботи nullable intз операторами less <and https://stackoverflow.com/a/51507612/7003760greater >

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