ternaria - La asociatividad del operador ternario en C#: ¿puedo confiar en ella?
operador ternario python (5)
Ahh, ¿no te encanta un buen abuso ternario? :) Considera la siguiente expresión:
true ? true : true ? false : false
Para aquellos de ustedes que ahora están completamente perplejos, les puedo decir que esto se evalúa como verdadero . En otras palabras, es equivalente a esto:
true ? true : (true ? false : false)
¿Pero es esto confiable? ¿Puedo estar seguro de que en algunas circunstancias no llegará a esto?
(true ? true : true) ? false : false
Algunos podrían decir: bueno, simplemente agregue paréntesis en ese momento o no lo use por completo. Después de todo, ¡es un hecho bien conocido que los operadores ternarios son malos!
Claro que sí, pero hay algunas circunstancias en las que realmente tienen sentido. Para los más curiosos, estoy retorciendo código que compara dos objetos por una serie de propiedades. Sería muy bueno si lo escribiera así:
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 y conciso. Pero sí depende de que la asociatividad del operador ternario funcione como en el primer caso. El paréntesis solo haría espaguetis con eso.
Entonces, ¿esto está especificado en alguna parte? No pude encontrarlo
Consulte msdn: http://msdn.microsoft.com/en-us/library/ty67wk28%28VS.80%29.aspx
"Si la condición es verdadera, la primera expresión se evalúa y se convierte en el resultado; si es falsa, la segunda expresión se evalúa y se convierte en el resultado. Sólo se evalúa una de cada dos expresiones".
La afirmación de que los paréntesis restan valor a la legibilidad del código es una suposición falsa. Encuentro la expresión entre paréntesis mucho más clara. Personalmente, usaría los paréntesis y / o reformatearía varias líneas para mejorar la legibilidad. El reformateo de varias líneas y el uso de la sangría puede incluso obviar la necesidad de paréntesis. Y, sí, puede confiar en el hecho de que el orden de asociación es determinista, de derecha a izquierda. Esto permite que la expresión se evalúe de izquierda a derecha de la manera 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);
Sí, puedes confiar en esto (no solo en C # sino en todos (que yo sepa) otros idiomas ( excepto PHP ... imagínate) con un operador condicional) y tu caso de uso es en realidad una práctica bastante común, aunque algunas personas lo aborrecen. .
La sección relevante en ECMA-334 (el estándar C #) es 14.13 §3:
El operador condicional es asociativo por la derecha, lo que significa que las operaciones se agrupan de derecha a izquierda. [Ejemplo: ¿Una expresión de la forma
a ? b : c ? d : e
a ? b : c ? d : e
a ? b : c ? d : e
se evalúa comoa ? b : (c ? d : e)
a ? b : (c ? d : e)
. ejemplo final]
Si tienes que preguntar, no lo hagas. Cualquier persona que lea su código solo tendrá que pasar por el mismo proceso que usted lo hizo, una y otra vez, en cualquier momento en que deba ver el código. La depuración de dicho código no es divertido. Eventualmente solo se cambiará para usar paréntesis de todos modos.
Re: "Trate de escribir todo el asunto CON paréntesis".
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))))
Aclaración:
- "Si tienes que preguntar, no lo hagas".
- "Cualquiera que esté leyendo tu código ..."
Seguir las convenciones comunes en un proyecto es cómo mantener la coherencia, lo que mejora la legibilidad. Sería una tarea absurda pensar que puede escribir un código legible para todos, ¡incluso para aquellos que ni siquiera saben el idioma!
Sin embargo, mantener la coherencia dentro de un proyecto es un objetivo útil, y no seguir las convenciones aceptadas de un proyecto lleva a un debate que impide que se resuelva el problema real. Se espera que los que lean su código conozcan las convenciones comunes y aceptadas que se utilizan en el proyecto, y es probable que sean alguien más que trabaje directamente en él. Si no los conocen, se espera que los aprendan y que sepan dónde acudir para obtener ayuda.
Dicho esto, si usar expresiones ternarias sin paréntesis es una convención común y aceptada en su proyecto, ¡entonces úselo, por todos los medios! Que tuvo que preguntar indica que no es común o aceptado en su proyecto. Si desea cambiar las convenciones en su proyecto, entonces haga lo que no es ambiguo, márquelo como algo para discutir con otros miembros del proyecto y continúe. Aquí eso significa usar paréntesis o usar if-else.
Un último punto para reflexionar, si alguno de sus códigos le parece inteligente:
La depuración es el doble de difícil que escribir el código en primer lugar. Por lo tanto, si escribe el código de la manera más inteligente posible, no es, por definición, lo suficientemente inteligente como para depurarlo. - Brian W. Kernighan
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;
Me gusta el primero.
Sí, puede confiar en la asociatividad condicional del operador. En el manual, en el enlace proporcionado amablemente por dcp, se indica como "El operador condicional es asociativo por derecho", con un ejemplo. Y, como usted sugirió y yo y otros acordamos, el hecho de que pueda confiar en él permite un código más claro.