Periodicamente, eu me pergunto sobre isso:
O OR de curto-circuito sempre retornaria o mesmo valor que o operador OU de curto-circuito.
Eu espero que o curto-circuito OU sempre avalie mais rapidamente. Então, o operador OR sem curtos-circuitos foi incluído na linguagem C # para consistência?
O que eu perdi?
f()
gera uma exceção, consideretrue || f()
etrue | f()
. Você vê a diferença? A expressão anterior é avaliada comotrue
, a avaliação dos últimos resulta em uma exceção sendo lançada.Respostas:
Ambos os operandos foram feitos para coisas diferentes, vindos de C, que não tinham um tipo booleano. A versão de curto-circuito || só funciona com booleanos, enquanto a versão sem curto-circuito | trabalha com tipos integrais, executando um bit a bit ou. Por acaso, funcionou como uma operação lógica de curto-circuito para booleanos, representados por um único bit, sendo 0 ou 1.
http://en.wikibooks.org/wiki/C_Sharp_Programming/Operators#Logical
fonte
|
operador, quando aplicado a dois valores booleanos, é compilado no mesmoor
operador no CIL e quando aplicado a dois valores inteiros - ao contrário do||
que é compilado no CIL usandobrtrue
para uma condição saltar.|
(o bit a bit ou) deve ser sem curto-circuito para tipos comoint
. Isso ocorre porque em quase todos os casos você precisa calcular os dois lados de uma|
expressão para calcular o resultado correto. Por exemplo, qual é o resultado7 | f(x)
?Se
f(x)
não é avaliado, você não pode dizer.Além disso, seria inconsistente fazer com que este operador sofra um curto-circuito
bool
, quando não for um curto-circuitoint
. A propósito, acho que nunca usei|
intencionalmente comparações lógicas, achando muito inconveniente falar|
como um operador lógico.||
no entanto, é para comparações lógicas, onde a avaliação de curto-circuito funciona bem.O mesmo vale para C e C ++, onde está a origem desses operadores.
fonte
Isso está correto, o operador OR de curto-circuito (||) sempre retornará o mesmo valor que o operador OR de não-curto-circuito (|). (*)
No entanto, se o primeiro operando for verdadeiro, o operador de curto-circuito não causará avaliação do segundo operando, enquanto o operador sem curto-circuito sempre causará avaliação de ambos os operandos. Isso pode ter um impacto no desempenho e, às vezes, em efeitos colaterais.
Portanto, existe uma utilidade para ambos: se você se importa com o desempenho e a avaliação do segundo operando não produz efeitos colaterais (ou se você não se importa com eles), então use o operador de curto-circuito . Mas se, por algum motivo, você precisar dos efeitos colaterais do segundo operando, use o operador que não seja de curto-circuito.
Um exemplo em que você deve usar o operador que não seja de curto-circuito:
(*) Exceto por um cenário realmente pervertido, em que a avaliação do primeiro operando como falso causa por efeito colateral o segundo operando a ser avaliado como verdadeiro em vez de falso.
fonte
Existem dois motivos para usar a variante não-curto-circuito:
mantendo efeitos colaterais (mas é mais claro codificar com uma variável temporária)
frustrar ataques de tempo evitando a bifurcação no curto-circuito (isso pode até melhorar a eficiência do tempo de execução se o segundo operando for uma variável, mas isso for uma micro-otimização que o compilador possa fazer de qualquer maneira)
fonte
se a cláusula direita do operador tiver efeito colateral, e o programador pretender que ele deseje que ambos os efeitos colaterais aconteçam antes de verificar seu valor de retorno.
fonte