¿Por qué es &&
preferible &
y ||
preferible |
?
Le pregunté a alguien que ha estado programando durante años y su explicación fue:
Por ejemplo, in if (bool1 && bool2 && bool3) { /*DoSomething*/ }
, bool1
tiene que ser verdadero para que pruebe bool2
cuál tiene que ser verdadero antes de continuar bool3
, etc. Si hubiera usado uno solo, &
no hay ningún orden para la prueba, incluso si todos tienen que ser fieles a avanzar a la siguiente línea, entonces, ¿por qué importa de todos modos?
Nota: Me gustaría señalar que soy el equivalente de programación de un niño pequeño y esta no es una pregunta seria o urgente. Es más una cuestión de entender por qué las cosas deben hacerse de cierta manera en lugar de otra.
x & y
yx && y
siempre evaluarán el mismo resultado si x e y son expresiones de tipo booleano. De hecho, la única diferencia en ese caso parece ser que enx & y
y siempre se evalúa.Respuestas:
En la mayoría de los casos,
&&
y||
se prefiere sobre&
y|
porque el primero se cortocircuitan-, lo que significa que la evaluación se cancela en cuanto el resultado es claro.Ejemplo:
Si
CanExecute
devuelvefalse
, la expresión completa seráfalse
, independientemente del valor de retorno deCanSave
. Debido a esto,CanSave
no se ejecuta.Esto es muy útil en las siguientes circunstancias:
TryGetValue
devuelvefalse
si la clave suministrada no se encuentra en el diccionario. Debido a la naturaleza de cortocircuito de&&
,value.Contains("test")
solo se ejecuta cuandoTryGetValue
regresatrue
y, por lo tanto,value
nonull
. Si utilizara el operador AND bit a bit en su&
lugar, obtendría unNullReferenceException
si la clave no se encuentra en el diccionario, porque la segunda parte de la expresión se ejecuta en cualquier caso.Un ejemplo similar pero más simple de esto es el siguiente código (como lo menciona TJHeuvel):
CanExecute
solo se ejecuta siop
no es asínull
. Siop
es asínull
, la primera parte de la expresión (op != null
) se evalúafalse
yop.CanExecute()
se omite la evaluación del resto ( ).Aparte de esto, técnicamente, son diferentes, también:
&&
y||
sólo se puede utilizar en labool
que,&
y|
se puede utilizar en cualquier tipo integral (bool
,int
,long
,sbyte
, ...), porque son operadores bit a bit.&
es el operador AND a nivel de bit y|
es el operador OR a nivel de bit .Para ser muy exactos, en C #, esos operadores (
&
,|
[y^
]) se denominan "operadores lógicos" (consulte la especificación de C # , capítulo 7.11). Hay varias implementaciones de estos operadores:int
,uint
,long
yulong
, capítulo 7.11.1):Se llevan a cabo para calcular el resultado bit a bit de los operandos y el operador, es decir,
&
es implementar para calcular la lógica bit a bitAND
etc.Se implementan para realizar la operación lógica del tipo subyacente de la enumeración.
El resultado no se calcula utilizando cálculos bit a bit. El resultado se busca básicamente en función de los valores de los dos operandos, porque el número de posibilidades es muy pequeño.
Debido a que ambos valores se usan para la búsqueda, esta implementación no está en cortocircuito.
fuente
if(op != null && op.CanExecute())
. Debido a que la segunda causa no se evalúa cuando la primera no es verdadera, esto es válido.TryGetValue
ejemplo. Pero sí, es otro buen ejemplo de esto.&
o|
se usa con argumentos no bool (es decir, lo que hacen los operadores) en beneficio de todas las personas nuevas.Explicar muy claramente lo que esto significa (aunque las otras respuestas lo insinúen, pero probablemente usen terminología que no entiendes).
El siguiente código:
Realmente está compilado para esto:
Donde el siguiente código se compila exactamente como se representa:
Esto se llama cortocircuito. En general, siempre debe usar
&&
y||
en sus condiciones.Marcas de bonificación: hay un escenario en el que no deberías. Si se encuentra en una situación en la que el rendimiento es crucial (y esto es crucial en nanosegundos ), solo use el cortocircuito cuando sea necesario (por ejemplo, la
null
comprobación), ya que un cortocircuito es una bifurcación / salto; lo que podría dar lugar a una predicción errónea de rama en su CPU; una&
es mucho más barato que&&
. También hay un escenario en el que los cortocircuitos en realidad pueden romper la lógica: eche un vistazo a esta respuesta mía.Diatribe / Monologue : con respecto a la predicción errónea de la rama que ignoramos con la mayor felicidad. Citando a Andy Firth (quien ha estado trabajando en juegos durante 13 años): "Este puede ser un nivel más bajo que la gente piensa que necesitan ir ... pero estarían equivocados. Comprender cómo el hardware que está programando para las ramas de golosinas puede afectar el rendimiento a un GRAN grado ... mucho más de lo que la mayoría de los programadores pueden apreciar re: muerte por mil cortes ".
Aquí hay un punto de referencia para los no creyentes. Es mejor ejecutar el proceso en tiempo real / alto para mitigar el planificador que tiene un efecto: https://gist.github.com/1200737
fuente
(x && y)
traduce aLOAD x; BRANCH_FALSE; LOAD y; BRANCH_FALSE;
donde se(x & y)
traduceLOAD x; LOAD y; AND; BRANCH_FALSE;
. Una rama versus dos.Operador lógico (
||
y&&
) vs. operador bit a bit (|
y&
).La diferencia más crucial entre un operador lógico y un operador bit a bit es que un operador lógico toma dos booleanos y produce un booleano, mientras que un operador bit a bit toma dos enteros y produce un entero (nota: enteros significa cualquier tipo de datos integral, no solo int).
Para ser pedante, un operador bit a bit toma un patrón de bits (por ejemplo, 01101011) y realiza un AND / OR en cada bit. Entonces, por ejemplo, si tiene dos enteros de 8 bits:
mientras que un operador lógico solo funciona en
bool
:En segundo lugar, a menudo es posible usar un operador bit a bit en bool ya que verdadero y falso es equivalente a 1 y 0 respectivamente, y sucede que si traduce verdadero a 1 y falso a 0, entonces realiza una operación a nivel de bit, luego convierte un valor distinto de cero a verdadero y cero a falso; sucede que el resultado será el mismo si hubiera utilizado el operador lógico (verifique esto para hacer ejercicio).
Otra distinción importante es también que un operador lógico está en cortocircuito . Por lo tanto, en algunos círculos [1], a menudo se ve gente haciendo algo como esto:
que se traduce como: "si la persona existe (es decir, no es nula), intente golpearla, y si el golpe tiene éxito (es decir, vuelve verdadero), entonces haga un baile de victoria" .
Si hubiera utilizado un operador bit a bit en su lugar, esto:
se traducirá a: "si la persona existe (es decir, no es nula) y el golpe tiene éxito (es decir, vuelve verdadero), entonces haga un baile de victoria" .
Tenga en cuenta que en el operador lógico en cortocircuito, el
person.punch()
código puede no ejecutarse siperson
es nulo. De hecho, en este caso particular, el segundo código produciría un error de referencia nulo siperson
es nulo, ya que intenta llamarperson.punch()
sin importar si la persona es nula o no. Este comportamiento de no evaluar el operando correcto se llama cortocircuito .[1] Algunos programadores criticarán por poner una llamada de función que tenga un efecto secundario dentro de una
if
expresión, mientras que para otros es un idioma común y muy útil.Dado que un operador bit a bit trabaja en 32 bits a la vez (si está en una máquina de 32 bits), puede generar un código más elegante y rápido si necesita comparar una gran cantidad de condiciones, por ejemplo
Hacer lo mismo con operadores lógicos requeriría una cantidad incómoda de comparaciones:
Un ejemplo clásico donde se usan patrones de bits y operadores bit a bit es en los permisos del sistema de archivos Unix / Linux.
fuente
En el caso de:
funcionaría como se esperaba.
Pero:
potencialmente podría lanzar una excepción de referencia nula.
fuente
Corto y simple:
1 && 2
= verdaderoporque
1 = verdadero (no cero) en C
2 = verdadero (no cero) en C
true
ANDS lógicamente contrue
dartrue
.Pero
1 & 2
= 0 = falsoporque
1 = 0001 en binario
2 = 0010 en binario
0001 ANDs a nivel de bit con 0010 para dar 0000 = 0 en decimal.
Del mismo modo para || y | operadores también ...!
fuente
1 && 2
es ilegal en C #&&
es la versión de corto circuito de&
.Si estamos evaluando
false & true
, ya sabemos al observar el primer argumento que el resultado será falso. La&&
versión del operador devolverá un resultado tan pronto como sea posible, en lugar de evaluar la expresión completa. También hay una versión alemana similar del|
operador,||
.fuente
es seguro
se bloquearía si la lista no tiene el tamaño correcto.
fuente
Los operadores de C # deben explicar por qué:
Esencialmente tener dos
&
's o|
' s significa que es condicional más que lógico, por lo que puede notar la diferencia entre los dos.& Operator tiene un ejemplo de uso de uno
&
.fuente
OK, en valor nominal
Producir la misma respuesta. Sin embargo, como mostró, si tiene una pregunta más compleja, entonces:
Si
a
no es cierto y tal vezb
es una función en la que tiene que apagarse, conectarse a algo, obtener esto, hacer eso, tomar una decisión ... ¿por qué molestarse? Pérdida de tiempo, ya sabes que ya ha fallado. ¿Por qué hacer que la máquina se apague y haga un trabajo extra sin sentido?Siempre lo he usado
&&
porque pongo los más propensos a fallar primero, ergo, menos cálculos antes de continuar cuando no tiene sentido. Si no hay forma de predecir opciones menos probables, como si tiene un valor booleano para limitar la salida de datos, algo como:Si no es así
limit
, no se moleste en buscar la clave, lo que podría llevar más tiempo.fuente
Cuando se usa en una expresión lógica como una declaración if
&&
preferible porque dejará de evaluar expresiones tan pronto como se encuentre el primer resultado falso. Esto es posible porque un valor falso hará que toda la expresión sea falsa. De manera similar (y nuevamente en expresiones lógicas)||
es preferible porque dejará de evaluar expresiones tan pronto como encuentre una expresión verdadera porque cualquier valor verdadero hará que toda la expresión sea verdadera.Sin embargo, si las expresiones de ser o de opinión o e-ed juntos tienen efectos secundarios, y desea que todo esto suceda como resultado de su expresión (sin importar el resultado de la expresión lógica), a continuación,
&
y|
podría ser utilizado. Por el contrario, los operadores&&
y||
pueden ser útiles como protección contra los efectos secundarios no deseados (como un puntero nulo que provoca una excepción).Los operadores
&
y|
también se pueden usar con enteros y, en este caso, producen un resultado entero que son los dos operandos y-ed o-ed juntos en el nivel de bit. Esto puede ser útil cuando los bits binarios de un valor entero se usan como una matriz de valores verdaderos y falsos. Para probar si un cierto bit está activado o desactivado, una máscara de bits se asigna a los bits y se edita con el valor. Para activar un bit, la misma máscara puede ser ordenada bit a bit con el valor. Finalmente, para desactivar un poco, el complemento a nivel de bit (usando~
) de una máscara es bit a bit con el valor.En lenguajes distintos de C #, se debe tener cuidado con los modos lógico versus bit a bit de & y |. En el código anterior, la
if
expresión condicional de la declaración(a & 4) != 0
es una forma segura de expresar esta condición, pero en muchos lenguajes similares a C, las declaraciones condicionales pueden simplemente tratar los valores enteros cero como valores enteros falsos y no cero como verdaderos. (La razón de esto se relaciona con las instrucciones de procesador de ramificación condicional disponibles y su relación con el indicador de cero que se actualiza después de cada operación de entero.) Por lo tantoìf
, la prueba de cero de la instrucción puede eliminarse y la condición podría acortarse(a & 4)
.Esto podría causar confusión e incluso problemas cuando las expresiones se combinen usando los valores de retorno bit a bit y del operador que no tienen bits que se alinean. Considere el siguiente ejemplo donde se desean los efectos secundarios de dos funciones, antes de verificar que ambos tuvieron éxito (según lo definido por ellos devolviendo un valor distinto de cero):
En C, si
foo()
devuelve 1 ybar()
devuelve 2, el "algo" no se hará porque1 & 2
es cero.C # requiere declaraciones condicionales como
if
tener un orandrand booleano, y el lenguaje no permite que un valor entero se convierta en un valor booleano. Entonces el código anterior generaría errores de compilación. Se expresaría más correctamente de la siguiente manera:fuente
Si eres un antiguo programador de C, ten cuidado . C # realmente me ha sorprendido.
MSDN dice para el
|
operador:(El énfasis es mío.) Los tipos booleanos se manejan especialmente, y en este contexto la pregunta solo comienza a tener sentido, y la diferencia es que, como otros ya se han expandido en sus respuestas:
y lo que es preferible depende de muchas cosas como los efectos secundarios, el rendimiento y la legibilidad del código, pero en general, los operadores de cortocircuito son preferibles también porque son mejor comprendidos por personas con antecedentes similares como yo.
La razón es: diría un argumento como este: dado que no hay un tipo booleano real en C, podría usar el operador bit a bit
|
y hacer que su resultado sea evaluado como verdadero o falso en una condición if. Pero esta es la actitud incorrecta para C #, porque ya existe un caso especial para los tipos booleanos.fuente
Es importante, porque si el costo de evaluación de bool2 (por ejemplo) es alto pero bool1 es falso, entonces se ha ahorrado un poco de cómputo utilizando && over &
fuente
Porque
&&
y||
se utilizan para el control de flujo tal comoif/else
son. No siempre se trata de condicionales. Es perfectamente razonable escribir como una declaración, no comoif
owhile
condicional, lo siguiente:o incluso
No es solo que sean más fáciles de escribir que las
if/else
versiones equivalentes ; También son mucho más fáciles de leer y entender.fuente
&& y & significan dos cosas muy diferentes y le dan dos respuestas diferentes.
1 && 2
produce 1 ("verdadero")1 & 2
produce 0 ("falso")&&
es un operador lógico; significa "verdadero si ambos operandos son verdaderos"&
es una comparación bit a bit. Significa "dime cuáles de los bits están configurados en ambos operandos"fuente
1 && 2
da un error de compilación: "Error 4 Operador '&&' no se puede aplicar a operandos de tipo 'int' e 'int'"La forma más rápida (y un poco tonta) de explicar esto a las personas que NO NECESITAN conocer las operaciones exactas del código cuando se hace esto
&& está haciendo una verificación de cada una de esas condiciones hasta que encuentre un falso y devuelva todo el resultado como falso
|| está haciendo una verificación de cada una de esas condiciones hasta que encuentra un verdadero y devuelve todo el resultado como verdadero.
& está haciendo MATHS basado en AMBAS / TODAS las condiciones y lidiando con el resultado.
El | está haciendo MATHS basado en AMBAS / TODAS las condiciones y lidiando con el resultado.
Nunca me he encontrado con un punto en el que haya necesitado usar & o | dentro de una declaración if. Principalmente lo uso para cortar valores hexadecimales en los colores de sus componentes usando el desplazamiento bit a bit.
P.EJ:
Dentro de esta operación "& 0xFF" está obligando a mirar solo el valor binario. No he encontrado personalmente un uso para |sin embargo.
fuente
Simplemente,
if exp1 && exp2
si exp1 es
flase
no marque exp2pero
if exp1 & exp2
si exp1 es
false
Otrue
verifique exp2y rara vez las personas usan
&
porque rara vez quieren verificar exp2 si exp1 esfalse
fuente