A clear, layman's explanation of the differenc

2019-01-10 11:10发布

Ok, so I've read about this a number of times, but I'm yet to hear a clear, easy to understand (and memorable) way to learn the difference between:

if (x | y)

and

if (x || y)

..within the context of C#. Can anyone please help me learn this basic truth, and how C# specifically, treats them differently (because they seem to do the same thing). If the difference a given piece of code has between them is irrelevant, which should I default to as a best-practise?

12条回答
Anthone
2楼-- · 2019-01-10 11:18

When used with boolean operands the | operator is a logical operator just as ||, but the difference is that the || operator does short circuit evaluation and the | operator does not.

This means that the second operand is always evaluated using the | operator, but using the || operator the second operand is only evaluated if the first operand evaluates to false.

The result of the expression is always the same for both operatrors, but if the evaluation of the second operand causes something else to change, that is only guaranteed to happen if you use the | operator.

Example:

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.

The short-circuit evaluation of the || operator can be used to write shorter code, as the second operand only is evaluated if the first operand is true. Instead of writing like this:

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

You can write like this:

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

The second operand is only evaluated if the first is false, so you know that you can safely use the string reference in the second operand as it can not be null if the second operand is evaluated.

In most cases you would want to use the || operator rather than the | operator. If the first operand is false, there is no need to evaluate the second operand to get the result. Also, a lot of people (evidently) doesn't know that you can use the | operator with boolean operands, so they would get confused when seeing it used that way in the code.

查看更多
劫难
3楼-- · 2019-01-10 11:19

Unlike what most of the answers so far say, the meaning is not exactly the same as in C++.

For any two expressions A and B evaluating to booleans, A || B and A | B do almost the same thing.

A | B evaluates both A and B, and if one of them evaluates to true, the result is true.

A || B does almost the same thing, except it evaluates A first, and then only evaluates B if it is necessary. Since the entire expression is true if either A or B is true, B doesn't need to be tested at all if A is true. So || short-circuits, and skips evaluating the second operand when possible, where the | operator will always evaluate both.

The | operator isn't often used, and often it won't make a difference. The only common case I can think of where it'd make a difference is this:

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

}

This works because the DoStuff() member function is never called if the left test fails. That is, if foo is null, we don't call DoStuff on it. (which would give us a NullReferenceException).

If we'd used the | operator, DoStuff() would be called regardless of whether foo was null or not.

On integers, only the | operator is defined, and is a bitwise OR, as the other answers describe. The || operator isn't defined for integer types though, so it's hard to get them mixed up in C#.

查看更多
SAY GOODBYE
4楼-- · 2019-01-10 11:20

They are not the same. One is bitwise OR and one is logical OR.

X || Y , is a logical or, means the same as "X or Y" and applies to bool values. It is used in conditionals or tests. X and Y in that case can be replaced with any expression that evaluates to a bool. Example:

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

The clause evaluates to true if either of the two conditions is true. If the first condition is true (if the file exists), then the second condition need not and will not be evaluated.

The single pipe ( | ) is a bitwise OR. To know what this means you must be understand how numbers are stored in the computer. Suppose you have a 16-bit quantity (Int16) that holds the value 15. It is actually stored as 0x000F (in hex) which is the same as 0000 0000 0000 1111 in binary. The bitwise OR takes two quantities and OR's each pair of corresponding bits together, so that if the bit is 1 in either quantity, it is 1 in the result. Therefore, if a = 0101 0101 0101 0101 (which evaluates to 0x5555 in hex) and b = 1010 1010 1010 1010 (which is 0xAAAA), then a | b = 1111 1111 1111 1111 = 0xFFFF.

You can use bitwise OR's (single pipe) in C# to test if one or more of a particular set of bits is turned on. You might do this if you have, let's say, 12 booleans or binary values to test for, and they are all independent. Suppose you have a student database. A set of independent booleans might be things like, male/female, home/on-campus, current/not-current, enrolled/not-enrolled, etc. Rather than store a boolean field for each one of those values, you could store just a single bit for each one. The male/female might be bit 1. enrolled/not might be bit 2.

Then you can use

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

as a test to see if no bits are turned on, except the "student is male" bit, which is ignored. Huh? Well, the bitwise OR returns a 1 for each bit that is on in either number. If the result of the bitwise OR above = 0x0001, that means there are no bits turned on in the bitfield, except maybe the first bit (0x0001), but you can't tell for sure whether the first bit is on, because it it is masked.

There is a corresponding && and &, which is logical AND and bitwise AND. They have the analogous behavior.

You can use

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

to see if the first bit is turned on in a bitfield.

EDIT: I can't believe I got voted down for this!

查看更多
The star\"
5楼-- · 2019-01-10 11:25

Strongly recommend to read this article from Dotnet Mob

For OR logical operation if any of it's operand is evaluated to true then whole expression is evaluated to true

this is what || Operator does - it skips the remaining evaluation when it found a true. While | Operator evaluate it's complete operands to asses the value of whole expression.

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
}

It is better to use Short Circuited version of Logical Operator Whether it is OR(||) or AND(&&) Operator.


Consider the following Code Snippet

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

This effect is called side effect, actually seen in right side of expression in short circuited logical operators

Reference : Short-circuit Evaluation in C#

查看更多
淡お忘
6楼-- · 2019-01-10 11:28

Without delving into the details in any way, shape, or form, here's a real layman's version.

Think of "|" as a straight "or" in english; think of "||" as "or else" in english.

Similarly think of "&" as "and" in english; think of "&&" as "and also" in english.

If you read an expression to yourself using these terms, they often make a lot more sense.

查看更多
神经病院院长
7楼-- · 2019-01-10 11:29

The first, bitwise operator works on two numerical values and results in a third one.

If you have binary variables

a = 0001001b;
b = 1000010b;

then

a | b == 1001011b;

That is, a bit in the result is 1 if it is also 1 in either of the operands. (My example uses 8-bit numbers for clarity's sake)

The "double pipe" ||, is a logical OR operator that takes two boolean values and results in a third.

查看更多
登录 后发表回答