Подтвердить что ты не робот

Тернарная ассоциативность операторов в С# - могу ли я на нее положиться?

Ах, разве ты просто не любишь хорошее тернарное насилие?:) Рассмотрим следующее выражение:

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)

Ясный и лаконичный. Но это зависит от тернарной операторной ассоциативности, работающей, как в первом случае. Скобки просто сделают из него спагетти.

Итак - это указано где угодно? Я не мог найти его.

4b9b3361

Ответ 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, указано как "условный оператор является право-ассоциативным", например. И, как вы предложили, и я и другие согласились, тот факт, что вы можете положиться на него, дает более четкий код.