Ясное, непрофессиональное объяснение разницы между | и || в c #?

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

if (x | y)

и

if (x || y)

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


person Ash    schedule 26.03.2009    source источник


Ответы (11)


|| - это оператор логическое ИЛИ. См. здесь. Он оценивается как 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, если хотя бы один из операндов истинен. Если применяется к целочисленным типам, он оценивает другое число. Это число имеет каждый бит, установленный в 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 истинно. По этой причине || считается "закорачивающим".

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

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

person Community    schedule 26.03.2009
comment
Imho, лучше всего использовать || и && (и избегайте | и &) - поскольку они используются более 99% времени, это, безусловно, стандартный подход. Написание нестандартного кода увеличивает вероятность ошибок. - Я бы сказал, что даже если вам нужно, чтобы оба операнда всегда оценивались, вам следует избегать | и & и реализовать его другим способом. - person Ellis; 26.11.2018

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

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

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

Пример:

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.

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

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);
}

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

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

person Guffa    schedule 26.03.2009
comment
Хотел бы я дать +10, это наиболее актуальный ответ, касающийся C #. Хотя все остальные технически правильны, они игнорируют тот факт, что вопрос относится к логической логике в C #. - person Robin Day; 26.03.2009
comment
Разве это не должно быть str! = Null? - person Les; 26.03.2009
comment
Нет, эта часть правильная, но первая часть мне кажется неправильной: int a = 0; int b = 0; bool x = (a! = 0 || ++ b! = 0); // здесь b по-прежнему 0, так как операнд ++ b! = 0 не был оценен Но a == 0, поэтому первая инструкция получает значение false, и поэтому оценивается вторая часть. - person Davy8; 26.03.2009
comment
@ Davy8: Да, вы правы, пример был неверным. Я исправил это. (Что касается форматирования кода; в комментариях форматирования нет вообще.) - person Guffa; 26.03.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 | б = 1111 1111 1111 1111 = 0xFFFF.

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

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

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

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

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

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

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

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

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

person Cheeso    schedule 26.03.2009
comment
| имеет другое значение в C #. Может быть, поэтому. - person jalf; 26.03.2009
comment
Более удивительно, что за вас проголосовали, поскольку ответ совершенно не имеет отношения к вопросу ... - person Guffa; 26.03.2009

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

person Tony the Pony    schedule 26.03.2009

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

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

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

А || 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 #.

person jalf    schedule 26.03.2009
comment
Написанный вами код неверен. Правильная форма: if (foo == null || foo.DoStuff()). Итак, если foo == null, выражение возвращает true без дальнейшего вычисления; в противном случае foo не равно нулю, поэтому первая часть возвращает ложь, а вторая часть оценивается, и это может быть так, поскольку в этом случае foo не равно нулю. - person Massimiliano Kraus; 30.06.2016

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

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

person cruizer    schedule 26.03.2009

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

if (x | y) 

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

if ( (x | y) != 0)

В C любое выражение, которое будет иметь бит «Вкл», приводит к истинному значению.

int я = 8;

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

int joy = -10;

if (joy) // действует в C, приводит к true

А теперь вернемся к 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; }
    }

is:

HeyJudeGet
Yes
HeyBack

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

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

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

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

person Michael Buen    schedule 26.03.2009

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

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

a = 0001001b;
b = 1000010b;

тогда

a | b == 1001011b;

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

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

person levik    schedule 26.03.2009

Не вдаваясь в подробности ни в каком виде или форме, вот настоящая версия для непрофессионала.

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

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

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

person Paul Suart    schedule 26.03.2009

Настоятельно рекомендую прочитать эту статью от 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 #

person Shamseer K    schedule 10.04.2015

Хотя это уже было сказано и дан правильный ответ, я подумал, что добавлю настоящий ответ непрофессионала, так как большую часть времени я чувствую себя на этом сайте :). Плюс я добавлю пример & vs. &&, поскольку это та же концепция

| vs ||

Обычно вы используете || когда вы хотите оценить только вторую часть, ЕСЛИ первая часть - ЛОЖЬ. Итак, это:

if (func1() || func2()) {func3();}

такой же как

if (func1())
{
    func3();
}
else 
{
    if (func2()) {func3();}
}

Это может быть способом сэкономить время обработки. Если для обработки func2 () потребовалось много времени, вы бы не захотели это делать, если func1 () уже была истинной.

& vs &&

В случае & vs. && это аналогичная ситуация, когда вы оцениваете только вторую часть, ЕСЛИ первая часть ИСТИНА. Например это:

if (func1() && func2()) {func3();}

такой же как

if (func1())
{
    if (func2()) {func3();}}
}

Это может быть необходимо, поскольку func2 () может зависеть от того, что func1 () сначала истинно. Если вы использовали & и func1 () с оценкой false, & все равно запустит func2 (), что может вызвать ошибку времени выполнения.

Джефф обыватель

person Jeff Keslinke    schedule 26.03.2009