Eu vou ser impopular e dizer Sim, é uma prática ruim. SE a funcionalidade do seu código depende dele para implementar lógica condicional.
ie
if(quickLogicA && slowLogicB) {doSomething();}
é bom, mas
if(logicA && doSomething()) {andAlsoDoSomethingElse();}
é ruim, e certamente ninguém concordaria ?!
if(doSomething() || somethingElseIfItFailed() && anotherThingIfEitherWorked() & andAlwaysThisThing())
{/* do nothing */}
Raciocínio:
Seu código erros se ambos os lados são avaliados em vez de simplesmente não executar a lógica. Argumentou-se que isso não é um problema, o operador 'e' é definido em c # para que o significado seja claro. No entanto, afirmo que isso não é verdade.
Razão 1. Histórico
Basicamente, você está confiando (no que foi originalmente planejado) em uma otimização de compilador para fornecer funcionalidade ao seu código.
Embora em c # a especificação da linguagem garanta que o operador booleano 'e' faça um curto-circuito. Isso não se aplica a todos os idiomas e compiladores.
O wikipeda lista vários idiomas e sua opinião sobre curtos-circuitos http://en.wikipedia.org/wiki/Short-circuit_evaluation, como você pode, existem muitas abordagens. E alguns problemas extras que não abordarei aqui.
Em particular, FORTRAN, Pascal e Delphi possuem sinalizadores de compilador que alternam esse comportamento.
Portanto: você pode achar que seu código funciona quando compilado para lançamento, mas não para depuração ou com um compilador alternativo etc.
Razão 2. Diferenças de idioma
Como você pode ver na wikipedia, nem todos os idiomas adotam a mesma abordagem para curtos-circuitos, mesmo quando especificam como os operadores booleanos devem lidar com isso.
Em particular, o operador 'and' do VB.Net não provoca curto-circuito e o TSQL tem algumas peculiaridades.
Dado que uma 'solução' moderna provavelmente incluirá vários idiomas, como javascript, regex, xpath etc., você deve levar isso em consideração ao tornar clara a funcionalidade do seu código.
Razão 3. Diferenças dentro de um idioma
Por exemplo, o inline do VB se comporta de maneira diferente do seu if. Novamente, em aplicativos modernos, seu código pode se mover entre, por exemplo, code-behind e um formulário da web embutido, você precisa estar ciente das diferenças de significado.
Razão 4. Seu exemplo específico de verificação nula do parâmetro de uma função
Este é um exemplo muito bom. É algo que todo mundo faz, mas é realmente uma prática ruim quando você pensa sobre isso.
É muito comum ver esse tipo de verificação, pois reduz consideravelmente suas linhas de código. Duvido que alguém o traga uma revisão de código. (e, obviamente, pelos comentários e classificações, você pode ver que é popular!)
No entanto, ele falha nas práticas recomendadas por mais de um motivo!
É muito claro, de várias fontes, que a melhor prática é verificar a validade de seus parâmetros antes de usá-los e lançar uma exceção se eles forem inválidos. Seu snippet de código não mostra o código circundante, mas você provavelmente deveria estar fazendo algo como:
if (smartphone == null)
{
//throw an exception
}
// perform functionality
Você está chamando uma função de dentro da instrução condicional. Embora o nome da sua função implique que ele simplesmente calcule um valor, ele pode ocultar efeitos colaterais. por exemplo
Smartphone.GetSignal() { this.signal++; return this.signal; }
else if (smartphone.GetSignal() < 1)
{
// Do stuff
}
else if (smartphone.GetSignal() < 2)
{
// Do stuff
}
as melhores práticas sugerem:
var s = smartphone.GetSignal();
if(s < 50)
{
//do something
}
Se você aplicar essas práticas recomendadas ao seu código, poderá ver que sua oportunidade de obter um código mais curto por meio do uso da condicional oculta desaparece. A melhor prática é fazer algo , lidar com o caso em que o smartphone é nulo.
Eu acho que você descobrirá que esse também é o caso de outros usos comuns. Você deve se lembrar que também temos:
condicionais em linha
var s = smartphone!=null ? smartphone.GetSignal() : 0;
coalescência nula
var s = smartphoneConnectionStatus ?? "No Connection";
que fornecem funcionalidade semelhante de tamanho de código curto com mais clareza
inúmeros links para apoiar todos os meus pontos:
https://stackoverflow.com/questions/1158614/what-is-the-best-practice-in-case-one-argument-is-null
Validação de parâmetro do construtor em C # - Melhores práticas
Deve-se procurar nulo se ele não espera nulo?
https://msdn.microsoft.com/en-us/library/seyhszts%28v=vs.110%29.aspx
https://stackoverflow.com/questions/1445867/why-would-a-language-not-use-short-circuit-evaluation
http://orcharddojo.net/orchard-resources/Library/DevelopmentGuidelines/BestPractices/CSharp
exemplos de sinalizadores do compilador que afetam o curto-circuito:
Fortran: "sce | nosce Por padrão, o compilador executa avaliação de curto-circuito em expressões lógicas selecionadas usando regras XL Fortran. A especificação de sce permite que o compilador use regras não-XL Fortran. O compilador executará avaliação de curto-circuito se as regras atuais permitirem O padrão é nosce. "
Pascal: "B - Uma diretiva de flag que controla a avaliação de curto-circuito. Consulte Ordem de avaliação de operandos de operadores diádicos para obter mais informações sobre avaliação de curto-circuito. Consulte também a opção do compilador -sc do compilador de linha de comando para obter mais informações ( documentado no manual do usuário). "
Delphi: "O Delphi suporta a avaliação de curto-circuito por padrão. Ele pode ser desativado usando a diretiva de compilador {$ BOOLEVAL OFF}."