Чому в C # часто бачимо "null! = Змінна" замість "varia!! = Null"?


103

У c #, чи є різниця у швидкості виплати для порядку, у якому ви заявляєте умову?

if (null != variable) ...
if (variable != null) ...

З недавнього часу я бачив перший досить часто, і це привернуло мою увагу, оскільки я звик до другого.

Якщо різниці немає, у чому перевага першого?



Деякі мови програмування підтримують ініціалізацію значення в умові if. У таких мовах, якщо ми хочемо порівняти LValue з RValue, це хороша практика використовувати буквений на лівий бік, наприклад, якщо (1 == i). так випадково, якщо ми поставимо = досить ==, то це дає помилку компілятора.
Джугал Панчал

Відповіді:


161

Це затримка від C. У C, якщо ви використовуєте поганий компілятор або не маєте попередження, підняті досить високо, це буде компілюватися без жодного попередження (і це дійсно юридичний код):

// Probably wrong
if (x = 5)

коли ти насправді мав на увазі

if (x == 5)

Ви можете обійти це на C, виконавши:

if (5 == x)

Опечатка тут призведе до недійсного коду.

Тепер у C # це все суворо. Якщо ви не порівнюєте два булевих значення (що рідко, IME), ви можете написати більш читабельний код, оскільки для оператора "якщо" потрібен булевий вираз, а тип " x=5" - це Int32, ні Boolean.

Я пропоную, якщо ви бачите це в коді своїх колег, ви навчаєте їх способам сучасних мов і пропоную їм написати більш природну форму в майбутньому.


6
Мої колеги всі змушують мене з цим і хочуть фігурних дужок навіть для однієї заяви після if ... (якщо ви додасте щось пізніше "не розуміючи"). Я скажу на F # і Boo (і YAML), якщо ваша мова не читається без відступів, зробіть її частиною мови.
Benjol

48
Додавання брекетів є розумним, IMO - C #, безумовно, не робить жодних спроб уникнути його проблеми. Це дуже відрізняється від питання "постійної == змінної".
Джон Скіт

6
a if (це! = що) {performAsSuch (); } насправді цілком здоровий. Аргумент "пізніше додавання" мені здається настільки тендітним, як не уникнути / зіпсувати, якщо (a = 5) помилки
jpinto3912

3
@jpinto: Я не зовсім впевнений , що ви намагаєтеся сказати тут , - що ви робите , як дужки навколо окремих операторів, або що у вас немає? Різниця між цим і змінним бізнесом у питанні полягає в тому, що в C # код з помилковим помилковим кодом, тому компілятор зупинить його. Те ж саме не стосується введення брекетів.
Джон Скіт,

3
@Benjol Не забувайте завжди вводити порожню else { }пропозицію, якщо комусь потрібно щось додати там пізніше, і забуде самостійно написати elseключове слово. (Жарт)
Jeppe Stig Nielsen

12

Є вагомий привід спочатку використовувати null: if(null == myDuck)

Якщо ваш class Duckпереосмислює ==оператора, тоді ви if(myDuck == null)можете перейти до нескінченного циклу.

При використанні nullспочатку використовується порівняльник рівності за замовчуванням і фактично робить те, що ви мали намір.

(Я чую, що ти звик читати код, написаний таким чином, зрештою, я просто ще не пережив цієї трансформації).

Ось приклад:

public class myDuck
{
    public int quacks;
    static override bool operator ==(myDuck a, myDuck b)
    {
        // these will overflow the stack - because the a==null reenters this function from the top again
        if (a == null && b == null)
            return true;
        if (a == null || b == null)
            return false;

        // these wont loop
        if (null == a && null == b)
            return true;
        if (null == a || null == b)
            return false;
        return a.quacks == b.quacks; // this goes to the integer comparison
    }
}

11
Це неправильно. Захищений. Просто наведіть курсор миші на ==оператора і вставте його там, і ви побачите, що визначене користувачем перевантаження використовується в обох випадках. Звичайно, це може суттєво змінитись, якщо перевірити aдо цього, bа потім поміняти положення aправого операнда на лівий операнд. Але ви також можете перевірити bраніше a, і тоді b == nullбуде той, який змінив порядок. Це все заплутано для того, щоб викликати оператор сам. Натомість киньте будь-який операнд (або обидва), objectщоб отримати бажане перевантаження. Як if ((object)a == null)і if (a == (object)null).
Jeppe Stig Nielsen

10

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

Просто візьміть цей простий приклад:

if(someVariableThatShouldBeChecked != null
   && anotherOne != null
   && justAnotherCheckThatIsNeededForTestingNullity != null
   && allTheseChecksAreReallyBoring != null
   && thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded != null)
{
    // ToDo: Everything is checked, do something...
}

Якщо ви просто поміняєте на початку всі нульові слова, ви можете набагато простіше помітити всі чеки:

if(null != someVariableThatShouldBeChecked
   && null != anotherOne
   && null != justAnotherCheckThatIsNeededForTestingNullity
   && null != allTheseChecksAreReallyBoring
   && null != thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded)
{
    // ToDo: Everything is checked, do something...
}

Отже, цей приклад може бути поганим прикладом (див. Рекомендації щодо кодування), але просто подумайте про те, як швидко прокрутити повний файл коду. Просто побачивши візерунок

if(null ...

ви відразу знаєте, що буде далі.

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


9

Я здогадуюсь, це програміст на C, який змінив мови.

На мові C можна написати наступне:

int i = 0;
if (i = 1)
{
    ...
}

Зауважте, що там використовується єдиний знак рівності, що означає, що код призначить 1 змінній i, потім поверне 1 (присвоєння - це вираз) та використовує 1 у if-операторі, який буде оброблятися як істинний. Іншими словами, вищезгадане - помилка.

Однак у C # це неможливо. Дійсно між ними немає різниці.


1
"У C #, однак, це неможливо", без того, щоб компілятор поскаржився, оскільки оператор if вимагає булевого вираження, а наданий має тип int.
Роберт Харві

4

У попередні часи люди забували б "!" (або додатковий '=' для рівності, який складніше помітити) і виконайте завдання замість порівняння. ставлення нуля спереду виключає можливість появи помилки, оскільки null не є l-значенням (IE йому не можна призначати).

Більшість сучасних компіляторів подають попередження, коли ви виконуєте завдання в умовному режимі, і C # насправді дає помилку. Більшість людей просто дотримуються схеми var == null, оскільки її легше читати.


Все C # Компілятори (зверніть увагу , що це C # питання) повинен скласти не «якщо» заяву , де вираз не є логічним , хоча ...
Джон Скит

4

Я не бачу жодної переваги в дотриманні цієї конвенції. У C, де булевих типів не існує, корисно писати

if( 5 == variable)

а не

if (variable == 5)

бо якщо ти забудеш один із еквальних знаків, то закінчишся

if (variable = 5)

який присвоює 5 змінній і завжди оцінює істину. Але на Яві булевий бул. І з! =, Зовсім немає причини.

Хоча одна хороша порада - написати

if (CONSTANT.equals(myString))

а не

if (myString.equals(CONSTANT))

оскільки це допомагає уникати NullPointerExceptions.

Моєю порадою було б попросити обґрунтування правила. Якщо його немає, навіщо його слідкувати? Це не допомагає читати


0

Для мене завжди було те, якому стилю ви віддаєте перевагу

@Shy - Потім, якщо ви заплутаєте операторів, тоді вам слід отримати помилку компіляції, або у вас буде запущений код із помилкою - помилкою, яка повернеться та кусає вас пізніше вниз по дорозі, оскільки це призвело до несподіваної поведінки


Я не думаю , що я коли - небудь чув, щоб хто краще «постійну == змінну» вид інший , ніж з міркувань безпеки, які вже мали справу з в C #.
Джон Скіт

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

1
Чи всі вони були люди з роками С промивання мізків за ними, чи це був справжній вибір?
Джон Скіт

0

Як багато хто зазначав, це здебільшого у старому коді С він використовувався для виявлення помилки компіляції, оскільки компілятор прийняв її як легальну

Нова мова програмування, як java, go, досить розумна, щоб фіксувати такі помилки компіляції

Не слід використовувати умови "null! = Variable" у коді, оскільки це дуже нечитабельно


-4

І ще одне ... Якщо ви порівнюєте змінну з константою (ціле число або рядок для прикладного), ставлення константи зліва - це хороша практика, тому що ви ніколи не зіткнетеся з NullPointerExceptions:

int i;
if(i==1){        // Exception raised: i is not initialized. (C/C++)
  doThis();
}

тоді як

int i;
if(1==i){        // OK, but the condition is not met.
  doThis();
}

Тепер, оскільки C # за замовчуванням створює всі змінні, у вас не повинно виникнути цієї проблеми на цій мові.


1
Я не впевнений, який компілятор ви використовуєте для першого біта коду, але він повинен компілюватися (як правило, з попередженням). Значення i не визначене, але воно має деяке значення.
Дельфін

Звичайно, обидва коди будуть складені! Саме в цьому і полягає проблема. Спробуйте запустити перший код, і ви зрозумієте, що я мав на увазі під винятком винятків ...
karlipoppins

також не отримати різниці між ними. Ви можете розвинути?
mfazekas

Не виняток, якщо ви не оголосите int * i в C / C ++, і навіть у такому випадку він буде порівнювати покажчики і не викидати жодного винятку ... Як і Дельфін, вказане значення не визначене, але воно не створить жодних винятків.
Cobusve

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