Тернарная ассоциативность операторов в С# - могу ли я на нее положиться?
Ах, разве ты просто не любишь хорошее тернарное насилие?:) Рассмотрим следующее выражение:
true ? true : true ? false : false
Для тех из вас, кто сейчас совершенно озадачен, могу сказать вам, что это оценивается как true. Другими словами, это эквивалентно этому:
true ? true : (true ? false : false)
Но разве это надежно? Могу ли я быть уверенным, что при некоторых обстоятельствах это не произойдет:
(true ? true : true) ? false : false
Некоторые могли бы сказать - ну, просто добавьте скобки или вообще не используйте его - в конце концов, это хорошо известный факт, что троичные операторы злы!
Конечно, они есть, но есть некоторые обстоятельства, когда они действительно имеют смысл. Для любопытных - я нажимаю код, который сравнивает два объекта по ряду свойств. Было бы неплохо, если бы я написал это так:
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)
Ясный и лаконичный. Но это зависит от тернарной операторной ассоциативности, работающей, как в первом случае. Скобки просто сделают из него спагетти.
Итак - это указано где угодно? Я не мог найти его.
Ответы
Ответ 1
Да, вы можете положиться на это (не только на С#, но и на всех (что я знаю) других языках (кроме PHP... go figure ) с условным оператором), и ваш прецедент на самом деле является довольно распространенной практикой, хотя некоторые люди отвращают его.
Соответствующий раздел в ECMA-334 (стандарт С#) равен 14.13 §3:
Условный оператор является право-ассоциативным, что означает, что операции группируются справа налево. [Пример: выражение формы a ? b : c ? d : e
оценивается как a ? b : (c ? d : e)
. конец пример]
Ответ 2
Если вам нужно спросить, не надо. Любой, кто читает ваш код, должен будет повторить тот же процесс, что и вы, снова и снова, в любое время, когда этот код нужно посмотреть. Отладка такого кода не приносит удовольствия. В конце концов, это будет просто изменено на использование круглых скобок.
Re: "Попробуйте написать все с круглыми скобками".
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))))
Разъяснение:
- "Если вы должны спросить, не делайте этого".
- "Любой, кто читает ваш код..."
В соответствии с общепринятыми в проекте соглашениями вы поддерживаете согласованность, которая улучшает читаемость. Было бы безумным поручением подумать, что вы можете написать код, читаемый всем и всем, включая тех, кто даже не знает языка!
Сохранение согласованности в рамках проекта, однако, является полезной целью, и не в соответствии с принятыми проектами конвенциями ведет к дебатам, которые умаляют решение реальной проблемы. Ожидается, что те, кто читает ваш код, будут знать об общих и принятых соглашениях, используемых в проекте, и даже, вероятно, кто-то другой будет работать непосредственно над ним. Если они не знают их, то они, как ожидается, будут изучать их и должны знать, куда обратиться за помощью.
Это говорит о том, что если использование трехмерных выражений без круглых скобок является общим и принятым соглашением в вашем проекте, тогда используйте его, во что бы то ни стало! То, что вы должны были спросить, указывает на то, что оно не является обычным или принятым в вашем проекте. Если вы хотите изменить соглашения в своем проекте, сделайте явно однозначный, отметьте его как что-то, что нужно обсудить с других участников проекта, и двигаться дальше. Здесь это означает использование скобок или использование if-else.
Последний момент для размышления, если какой-то из ваших кодов кажется вам умным:
Отладка в два раза сложнее, чем запись кода в первую очередь. Поэтому, если вы пишете код настолько умно, насколько это возможно, вы по определению недостаточно умны, чтобы его отлаживать. — Брайан У. Керниган
Ответ 3
Утверждение о том, что круглые скобки умаляют читаемость кода, является ложным предположением. Я считаю выражение в скобках более понятным. Лично я хотел бы использовать круглые скобки и/или переформатировать несколько строк для улучшения удобочитаемости. Переформатирование нескольких строк и использование отступов могут даже устранить необходимость в круглых скобках. И да, вы можете положиться на то, что порядок ассоциации детерминирован, справа налево. Это позволяет вычислять выражение слева направо ожидаемым образом.
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);
Ответ 4
Обратитесь к msdn:
http://msdn.microsoft.com/en-us/library/ty67wk28%28VS.80%29.aspx
"Если условие истинно, первое выражение оценивается и становится результатом, а если false, второе выражение оценивается и становится результатом. Только одно из двух выражений всегда оценивается."
Ответ 5
x = cond1 ? result1
: cond2 ? result2
: cond3 ? result3
: defaultResult;
против
if (cond1) x = result1;
else if (cond2) x = result2;
else if (cond3) x = result3;
else x = defaultResult;
Мне нравится первый.
Да, вы можете положиться на ассоциативную ассоциативность операторов. Его в руководстве, на ссылке, любезно предоставленной dcp, указано как "условный оператор является право-ассоциативным", например. И, как вы предложили, и я и другие согласились, тот факт, что вы можете положиться на него, дает более четкий код.