Difference between eager operation and short-circuit operation? (| versus || and & versus &&)
I am (still) learning C# - and I thought I understood the difference between &
& &&
as well as |
& ||
...
However, after just reading another guide, it is clear I don't get it.
I wrote a little truth table and as I thought, they return the same. From what I have read, using double symbols sounds like a superior solution, but I am a little confused on the difference and was wondering if anyone could please explain/give an example why/when you would use one ins开发者_如何学Ctead of the other - I tried reading the MSDN example, but it left me more confused than when I started!
(And, if anyone can come up with a better title, feel free to change it... very awkward to write one!)
& can be used in two different ways: bitwise "and" and logical "and"
The difference between logical & and && is only that in case you use &, the second expression is also evaluated, even if the first expression was already false. This may (for example) be interesting if you want to initialize two variables in the loop:
if ((first = (i == 7)) & (second = (j == 10))) { //do something }
if you use this syntax, first and second will always have a value, if you use
if ((first = (i == 7)) && (second = (j == 10))) { //do something }
it may be that only first has a value after the evaluation.
It is the same for | and ||: In case you use |, both of the expressions are always evaluated, if you use || it may be that only the first expression is evaluated, which would be the case if the first expression is true.
In contrast, in other applications && can be the better choice. If myNumber is of type int?
, you could have something like
if (myNumber != null && myNumber.Value == 7)
and this would only evaluate myNumber != null
at first, and it would only evaluate the second expression, if the null check was okay.
if (myNumber != null & myNumber.Value == 7)
would finish with a NullPointerException during the evaluation of the second expression, if myNumber was null. Therefore, you would use && in this context.
you should read this Short-circuit evaluation.
&& and || are used with booleans. Your output makes sense when using these.
& and | are bitwise operator, meaning they are applied to the operands bit by bit. For example
110010010 |
001000100 =
111010110
using the same table of your program's output but a bit a time. They are mainly used with integers, not booleans.
The difference will be less apparent in booleans; bitwise operators are primarily for numbers, whereas logical operators are primarily for booleans. In a bitwise operation (e.g., &), the operation is performed for each bit. In a logical operation (e.g., &&), the operation is performed for the entire result.
For example, the bitwise & of 11 (1011 in binary) and 2 (10 in binary) would be computed as such:
1011
& 0010
______
0010
which is 2.
There is an additional consideration in how the two types of operators are executed. When using a bitwise operator, the expressions on either side of the operator are first executed, and then the operation is performed. When using a logical operator, however, the expression on the left side of the operator is performed first, and the right side may be neglected if it will not change the result.
For example, when I execute (false expression) && (true expression)
, the true expression is never evaluated. Likewise with (true expression) || (false expression)
. This is referred to as short-circuit evaluation
Bitwise operations are used on integers. You must view the entire integer as 32 individual bits. Most .NET developers rarely use bitwise operations. Check out wikipedia for more clarification.
I think you are getting tripped up because C# has overloaded |
and &
. Used with numeric primitives then they are bitwise operations. Used with booleans then they are just like ||
and &&
except they don't short circuit.
For example
bool Foo() {
return false;
}
bool Bar() {
return true;
}
if(Foo() & Bar()) {
// do something
}
// versus
if(Foo() && Bar()) {
// do something 2
}
In the above example, the first boolean expression will execute both Foo() and Bar(), but in the second one only Foo() will execute.
IMO this is one of the worst decisions the C# team has made. It leads to confusing and occasionally subtle errors.
When using booleans there is no difference. The difference becomes more noticable when writing
1 & 2 = 3
1 && 2 = Error // Not 'true' as I wrote before. It would be in C++, but not in C#.
The double operator is a logical operator. It will treat each side as a boolean and returns a boolean that tells you something about these values (operands).
The single operator is a bitwise operator. It takes all bits in each value, performs the boolean logic on those bits, and combines the resulting bits into a new value.
Because a boolean value contains only one bit, the result for boolean operands is the same when using single (bitwise) or double (logical) operator, but since you're (probably) doing some logical operations, it's logical to use the logical operator too. (no pun intended)
精彩评论