Четкое, непрофессиональное объяснение разницы между | и || в с #? - PullRequest
45 голосов
/ 26 марта 2009

Хорошо, так что я читал об этом несколько раз, но мне еще предстоит услышать ясный, легкий для понимания (и запоминающийся) способ узнать разницу между:

if (x | y)

и

if (x || y)

.. в контексте C #. Может кто-нибудь, пожалуйста, помогите мне узнать эту основную истину, и, как C # конкретно, относится к ним по-разному (потому что они, кажется, делают то же самое) Если разница между этими частями кода не имеет значения, какую из них я должен использовать по умолчанию?

Ответы [ 11 ]

82 голосов
/ 26 марта 2009

|| является логическим оператором или . См. здесь . Он оценивается как true, если хотя бы один из операндов имеет значение true. Вы можете использовать его только с булевыми операндами; ошибочно использовать его с целочисленными операндами.

// Example
var one = true || bar();   // result is true; bar() is never called
var two = true | bar();    // result is true; bar() is always called

| - это оператор или . См. здесь . При применении к логическим типам, оно оценивается как true, если хотя бы один из операндов имеет значение true. Применительно к целочисленным типам он оценивается как другое число. Для этого числа каждый из его битов установлен в 1, если хотя бы для одного из операндов установлен соответствующий бит.

// Example
var a = 0x10;
var b = 0x01;
var c = a | b;     // 0x11 == 17
var d = a || b;    // Compile error; can't apply || to integers
var e = 0x11 == c; // True

Для логических операндов a || b идентичен a | b, с единственным исключением, что b не оценивается, если a имеет значение true. По этой причине || называется "короткозамкнутым".

Если разница между этими частями кода не имеет значения, какую из них я должен использовать по умолчанию в качестве передового опыта?

Как уже отмечалось, разница не имеет значения, поэтому этот вопрос является частично спорным. Что касается «лучшей практики», ее нет: вы просто используете тот оператор, который вам подходит. В общем, люди предпочитают || над | для булевых операндов, так как вы можете быть уверены, что это не приведет к ненужным побочным эффектам.

44 голосов
/ 26 марта 2009

При использовании с булевыми операндами оператор | является логическим оператором, аналогичным ||, но отличие состоит в том, что оператор || выполняет оценку короткого замыкания, а оператор | - нет.

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

Результат выражения всегда одинаков для обеих ошибок, но если вычисление второго операнда вызывает изменение чего-то другого, это гарантированно произойдет только при использовании оператора |.

Пример:

int a = 0;
int b = 0;

bool x = (a == 0 || ++b != 0);

// here b is still 0, as the "++b != 0" operand was not evaluated

bool y = (a == 0 | ++b != 0);

// here b is 1, as the "++b != 0" operand was evaluated.

Оценка короткого замыкания оператора || может использоваться для записи более короткого кода, поскольку второй операнд оценивается только в том случае, если первый операнд имеет значение true. Вместо того, чтобы писать так:

if (str == null) {
   Console.WriteLine("String has to be at least three characters.");
} else {
   if (str.Length < 3) {
      Console.WriteLine("String has to be at least three characters.");
   } else{
      Console.WriteLine(str);
   }
}

Вы можете написать так:

if (str == null || str.Length < 3) {
   Console.WriteLine("String has to be at least three characters.");
} else{
   Console.WriteLine(str);
}

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

В большинстве случаев вы захотите использовать оператор || вместо оператора |. Если первый операнд имеет значение false, нет необходимости оценивать второй операнд, чтобы получить результат. Кроме того, многие люди (очевидно) не знают, что вы можете использовать оператор | с булевыми операндами, поэтому они могут запутаться, увидев, как он используется таким образом в коде.

10 голосов
/ 26 марта 2009

Они не одинаковы. Один является побитовым ИЛИ, а другой - логическим ИЛИ.

X || Y, является логическим или, означает то же самое, что и «X или Y» и применяется к значениям bool. Используется в условных выражениях или тестах. X и Y в этом случае могут быть заменены любым выражением, которое оценивается как bool. Пример:

if (File.Exists("List.txt")  ||  x > y )  { ..}

Предложение оценивается как истинное, если выполняется одно из двух условий. Если первое условие истинно (если файл существует), то второе условие не нужно и не будет оцениваться.

Одиночная труба (|) является побитовым ИЛИ. Чтобы знать, что это значит, вы должны понимать, как числа хранятся на компьютере. Предположим, у вас есть 16-разрядное количество (Int16), которое содержит значение 15. На самом деле оно хранится как 0x000F (в шестнадцатеричном формате), что соответствует 0000 0000 0000 1111 в двоичном виде. Побитовое ИЛИ принимает две величины и каждую пару соответствующих битов ИЛИ вместе, так что если бит равен 1 в любом количестве, он равен 1 в результате. Следовательно, если a = 0101 0101 0101 0101 (который оценивается в 0x5555 в шестнадцатеричном виде) и b = 1010 1010 1010 1010 (что равно 0xAAAA), то a | b = 1111 1111 1111 1111 = 0xFFFF.

Вы можете использовать побитовое ИЛИ (одиночный канал) в C #, чтобы проверить, включен ли один или несколько из определенного набора битов. Вы можете сделать это, если у вас есть, скажем, 12 логических или двоичных значений для проверки, и все они независимы. Предположим, у вас есть база данных студентов. Набором независимых логических значений могут быть такие вещи, как «мужчина / женщина», «дом / на кампусе», «текущий / не текущий», «зарегистрирован / не зарегистрирован» и т. Д. Вместо того, чтобы хранить логическое поле для каждого из этих значений, вы можете сохранить только один бит для каждого. Мужской / женский может быть бит 1. зарегистрирован / не может быть бит 2.

Тогда вы можете использовать

 if ((bitfield | 0x0001) == 0x0001) { ... }

в качестве теста, чтобы увидеть, включены ли никакие биты, кроме бита "студент-мужчина", который игнорируется. А? Ну, побитовое ИЛИ возвращает 1 для каждого бита, который включен в любом числе. Если результат побитового ИЛИ выше = 0x0001, это означает, что в битовом поле нет включенных битов, за исключением возможно первого бита (0x0001), но вы не можете точно сказать, является ли первый бит включен, потому что он замаскирован.

Существует соответствующий && и &, который является логическим И и побитовым И. У них аналогичное поведение.

Вы можете использовать

 if ((bitfield &  0x0001) == 0x0001) { ... }

чтобы увидеть, включен ли первый бит в битовом поле.

РЕДАКТИРОВАТЬ: Я не могу поверить, что меня за это проголосовали!

5 голосов
/ 26 марта 2009

В отличие от того, что говорится в большинстве ответов, значение не точно такое же, как в C ++.

Для любых двух выражений A и B с булевыми значениями A || Б и А | B делает почти то же самое.

А | B оценивает и A и B, и если один из них оценивается как true, результат равен true.

A || B делает почти то же самое, за исключением того, что сначала оценивает A, а затем оценивает B, только если это необходимо. Поскольку все выражение истинно, если A или B истинно, B вообще не нужно проверять, если A истинно. Так что || коротких замыканий и пропускает оценку второго операнда, когда это возможно, где | Оператор всегда оценит оба.

| оператор не часто используется, и часто это не будет иметь значения. Единственный общий случай, который я могу придумать, где это будет иметь значение, это:

if ( foo != null || foo.DoStuff()){ // assuming DoStuff() returns a bool

}

Это работает, потому что функция-член DoStuff () никогда не вызывается, если левый тест не пройден. То есть, если foo равно null, мы не вызываем DoStuff для него. (что даст нам исключение NullReferenceException).

Если бы мы использовали | Оператор DoStuff () будет вызываться независимо от того, был ли foo нулевым или нет.

Для целых чисел только | оператор определен и является побитовым ИЛИ, как описывают другие ответы. || Оператор не определен для целочисленных типов, поэтому их сложно спутать в C #.

5 голосов
/ 26 марта 2009

Хорошие ответы, но позвольте мне добавить, что правые выражения для || не оцениваются, если левое выражение равно true. Помните об этом в случаях, когда условия оценки являются: а) интенсивными по производительности или б) производят побочные эффекты (редко).

4 голосов
/ 26 марта 2009

| является побитовым оператором ИЛИ (числовое, целое). он работает путем преобразования чисел в двоичные и выполнения ИЛИ для каждой из соответствующих цифр. опять же, числа уже представлены в двоичном виде на компьютере, поэтому во время выполнения такого преобразования не происходит;)

|| логический оператор ИЛИ (логический) он работает только с истинными и ложными значениями.

3 голосов
/ 26 марта 2009

Следующее будет работать в C / C ++, потому что он не поддерживает булевы классы первого класса, он рассматривает каждое выражение с битом on на них как true, иначе false. Фактически, следующий код не будет работать в C # или Java, если x и y имеют числовые типы.

if (x | y) 

Итак, явная версия приведенного выше кода:

if ( (x | y) != 0)

В C любое выражение, в котором есть бит "On", приводит к true

int i = 8;

если (i) // допустимо в C, приводит к истине

int joy = -10;

if (радость) // vaild в C, приводит к истине

Теперь вернемся к C #

Если x и y имеют числовой тип, ваш код: if (x | y) не будет работать. Вы пытались его скомпилировать? Не получится

Но для вашего кода, который я могу предположить, x и y относятся к логическим типам, поэтому он будет работать, поэтому разница между | и || для логических типов || короткозамкнут, | не является. Вывод следующий:

    static void Main()
    {


        if (x | y)
            Console.WriteLine("Get");

        Console.WriteLine("Yes");

        if (x || y)
            Console.WriteLine("Back");

        Console.ReadLine();
    }


    static bool x
    {
        get { Console.Write("Hey");  return true; }
    }

    static bool y
    {
        get { Console.Write("Jude"); return false; }
    }

есть:

HeyJudeGet
Yes
HeyBack

Джуд не будет напечатан дважды, || является логическим оператором, многие логические операторы на языках Си имеют короткие замыкания , логические выражения более производительны, если они закорочены.

Что касается непрофессиональных терминов, когда вы говорите короткозамкнутым, например, в || (или оператор), если первое выражение уже верно, нет необходимости оценивать второе выражение. Пример: если (answer == 'y' || answer == 'Y'), если пользователь нажимает маленькое y, программе не нужно вычислять второе выражение (answer == 'Y'). Это короткое замыкание.

В моем примере кода выше X - это правда, поэтому Y на || Оператор не будет оцениваться дальше, следовательно, нет второго выхода "Джуд".

Не используйте этот тип кода в C #, даже если X и Y имеют логические типы: if (x | y) . Не исполнитель.

2 голосов
/ 10 апреля 2015

Настоятельно рекомендуем прочитать эту статью от Dotnet Mob

Для логической операции ИЛИ, если любой из ее операндов оценивается как истина, то все выражение оценивается как истинное

вот что || Оператор делает - он пропускает оставшуюся оценку, когда он нашел истину. В то время как | Оператор оценивает свои полные операнды, чтобы оценить значение всего выражения.

if(true||Condition1())//it skip Condition1()'s evaluation
{
//code inside will be executed
}
if(true|Condition1())//evaluates Condition1(), but actually no need for that
{
//code inside will be executed
}

Лучше использовать версию логического оператора с коротким замыканием, будь то оператор ИЛИ (||) или И (&&). <ч /> Рассмотрим следующий фрагмент кода

int i=0;
if(false||(++i<10))//Now i=1
{
//Some Operations
}
if(true||(++i<10))//i remains same, ie 1
{}

Этот эффект называется побочный эффект , фактически видимый в правой части выражения в короткозамкнутых логических операторах

Ссылка: Оценка короткого замыкания в C #

2 голосов
/ 26 марта 2009

Не вдаваясь в детали, каким-либо образом, в какой-либо форме, вот версия real layman.

Подумайте о "|" как прямой "или" на английском языке; думать о "||" как "или иначе" на английском языке.

Точно так же думайте о «&» как «и» на английском языке; Думайте о "&&" как "а также" на английском языке.

Если вы читаете выражение себе, используя эти термины, они часто имеют гораздо больше смысла.

2 голосов
/ 26 марта 2009

Первый побитовый оператор работает с двумя числовыми значениями и приводит к третьему.

Если у вас есть двоичные переменные

a = 0001001b;
b = 1000010b;

затем

a | b == 1001011b;

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

«Двойная труба» ||, это логический оператор ИЛИ, который принимает два логических значения и приводит к третьему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...