Pergunta

Ahh, você não ama um bom abuso ternário? :) Considere a seguinte expressão:

true ? true : true ? false : false

Para aqueles que agora estão totalmente perplexos, posso dizer que isso avalia verdadeiro. Em outras palavras, é equivalente a isso:

true ? true : (true ? false : false)

Mas isso é confiável? Posso ter certeza de que, em algumas circunstâncias, não chegará a isso:

(true ? true : true) ? false : false

Alguns podem dizer - Bem, basta adicionar parênteses então ou não usá -lo completamente - afinal, é um fato bem conhecido que os operadores ternários são maus!

Claro que estão, mas há algumas circunstâncias quando eles realmente fazem sentido. Para os curiosos - estou colando código que compara dois objetos por uma série de propriedades. Seria muito bom se eu escreva frio assim:

obj1.Prop1 != obj2.Prop1 ? obj1.Prop1.CompareTo(obj2.Prop1) :
obj1.Prop2 != obj2.Prop2 ? obj1.Prop2.CompareTo(obj2.Prop2) :
obj1.Prop3 != obj2.Prop3 ? obj1.Prop3.CompareTo(obj2.Prop3) :
obj1.Prop4.CompareTo(obj2.Prop4)

Claro e conciso. Mas isso depende da associativa do operador ternário que funciona como no primeiro caso. Parênteses apenas fazia espaguete com isso.

Então - isso é especificado em algum lugar? Eu não consegui encontrar.

Foi útil?

Solução

Sim, você pode confiar nisso (não apenas em C#, mas em tudo (que eu conheço) outros idiomas (exceto php … Vá imaginar) com um operador condicional) e seu caso de uso é na verdade uma prática bastante comum, embora algumas pessoas a abominem.

A seção relevante na ECMA-334 (o padrão C#) é 14.13 §3:

O operador condicional é associado à direita, o que significa que as operações são agrupadas da direita para a esquerda. [Exemplo: uma expressão do formulário a ? b : c ? d : e é avaliado como a ? b : (c ? d : e). Exemplo final

Outras dicas

Se você tiver que perguntar, não. Qualquer pessoa que leia seu código terá que passar pelo mesmo processo que você fez, repetidamente, algum Tempo em que o código precisa ser analisado. Debugando esse código não é divertido. Eventualmente, ele será alterado para usar parênteses de qualquer maneira.

Ré: "Tente escrever a coisa toda com parênteses."

result = (obj1.Prop1 != obj2.Prop1 ? obj1.Prop1.CompareTo(obj2.Prop1) :
         (obj1.Prop2 != obj2.Prop2 ? obj1.Prop2.CompareTo(obj2.Prop2) :
         (obj1.Prop3 != obj2.Prop3 ? obj1.Prop3.CompareTo(obj2.Prop3) :
                                     obj1.Prop4.CompareTo(obj2.Prop4))))

Esclarecimento:

  • "Se vocês tem que perguntar, não. "
  • "Qualquer pessoa lendo sua código..."

Seguir as convenções comuns em um projeto é como você mantém a consistência, o que melhora a legibilidade. Seria uma tarefa de tolo pensar que você pode escrever um código legível para todos - incluindo aqueles que nem conhecem o idioma!

Manter a consistência dentro de um projeto, no entanto, é uma meta útil, e não seguir as convenções aceitas de um projeto leva ao debate que prejudica a solução do problema real. Espera -se que aqueles que lêem seu código estejam cientes das convenções comuns e aceitas usadas no projeto e provavelmente sejam alguém que trabalhe diretamente nele. Se eles não os conhecem, espera -se que eles os aprendam e devem saber onde procurar ajuda.

Dito isto - se usar expressões ternárias sem parênteses é uma convenção comum e aceita em seu projeto, use -a, por todos os meios! O que você teve que perguntar indica que não é comum ou aceito em seu projeto. Se você deseja alterar as convenções em seu projeto, faça o obviamente inequívoco, marque -o como algo para discutir com outros membros do projeto e seguir em frente. Aqui isso significa usar parênteses ou usar if-else.

Um ponto final a ponderar, se parte do seu código parecer inteligente para você:

A depuração é duas vezes mais difícil do que escrever o código em primeiro lugar. Portanto, se você escrever o código da maneira mais inteligente possível, você é, por definição, não é inteligente o suficiente para depurar. - Brian W. Kernighan

A afirmação de que os parênteses prejudicam a legibilidade do código é uma suposição falsa. Acho a expressão entre parênteses muito mais clara. Pessoalmente, eu usaria os parênteses e/ou reformatados em várias linhas para melhorar a legibilidade. Reformatando sobre várias linhas e o uso de recuo pode até evitar a necessidade de parênteses. E, sim, você pode confiar no fato de que a ordem da associação é determinística, direita para a esquerda. Isso permite que a expressão avalie a esquerda para a direita da maneira esperada.

obj1.Prop1 != obj2.Prop1
     ? obj1.Prop1.CompareTo(obj2.Prop1)
     : obj1.Prop2 != obj2.Prop2
           ? obj1.Prop2.CompareTo(obj2.Prop2)
           : obj1.Prop3 != obj2.Prop3
                  ? obj1.Prop3.CompareTo(obj2.Prop3)
                  : obj1.Prop4.CompareTo(obj2.Prop4);

Consulte o MSDN:http://msdn.microsoft.com/en-us/library/ty67wk28%28vs.80%29.aspx

"Se a condição for verdadeira, a primeira expressão é avaliada e se torna o resultado; se falsa, a segunda expressão é avaliada e se torna o resultado. Apenas uma das duas expressões é avaliada".

x = cond1 ? result1
  : cond2 ? result2
  : cond3 ? result3
  : defaultResult;

vs.

if (cond1) x = result1;
else if (cond2) x = result2;
else if (cond3) x = result3;
else x = defaultResult;

Eu gosto da primeira.

Sim, você pode confiar na associativa do operador condicional. Está no manual, no link gentilmente fornecido pelo DCP, declarado como "o operador condicional é associativo correto", com um exemplo. E, como você sugeriu e eu e outros concordamos, o fato de você poder confiar nele permite um código mais claro.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top