Ассоциативность троичных операторов в C # - могу ли я на это положиться? - PullRequest
17 голосов
/ 19 ноября 2009

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

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)

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

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

Ответы [ 5 ]

22 голосов
/ 19 ноября 2009

Да, вы можете положиться на это (не только в C #, но и на всех (которые я знаю) других языках (, кроме PHP ... go figure) с условным оператором), и ваш вариант использования фактически довольно распространенная практика, хотя некоторые люди ненавидят ее.

Соответствующий раздел в ECMA-334 (стандарт C #) - 14.13 §3:

Условный оператор является ассоциативным справа, что означает, что операции сгруппированы справа налево. [Пример: выражение вида a ? b : c ? d : e оценивается как a ? b : (c ? d : e). конец пример]

17 голосов
/ 19 ноября 2009

Если вам нужно спросить, не надо. Любой, кто читает ваш код, просто должен будет проходить один и тот же процесс, который вы делали, снова и снова, в любое время, когда необходимо просмотреть код. Отлаживать такой код не весело. В конце концов, это все равно будет изменено на использование скобок.

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.

Последнее замечание, если какой-то код кажется вам умным:

Отладка в два раза сложнее, чем писать код в первую очередь. Поэтому, если вы пишете код настолько умно, насколько это возможно, вы, по определению, недостаточно умны для его отладки. & Mdash; Брайан В. Керниган

4 голосов
/ 19 ноября 2009

Утверждение, что круглые скобки ухудшают читабельность кода, является ложным предположением. Я нахожу выражение в скобках гораздо яснее. Лично я бы использовал круглые скобки и / или переформатировал несколько строк для улучшения читабельности. Переформатирование в несколько строк и использование отступов может даже устранить необходимость в скобках. И, да, вы можете положиться на тот факт, что порядок ассоциации является детерминированным, справа налево. Это позволяет выражению вычислять слева направо ожидаемым образом.

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

1 голос
/ 19 ноября 2009

Обратитесь к msdn: http://msdn.microsoft.com/en-us/library/ty67wk28%28VS.80%29.aspx

"Если условие истинно, первое выражение оценивается и становится результатом; если ложно, второе выражение оценивается и становится результатом. Всегда вычисляется только одно из двух выражений."

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...