Условный оператор C # не является утверждением?

У меня есть простой небольшой фрагмент кода, который меня расстраивает:

HashSet<long> groupUIDs = new HashSet<long>();
groupUIDs.Add(uid)? unique++ : dupes++;

Во время компиляции он генерирует ошибку:

В качестве оператора можно использовать только выражения присваивания, вызова, увеличения, уменьшения и нового объекта.

HashSet.Add задокументирован для возврата логического значения, поэтому тернарный оператор (?) Должен работать, и это выглядит как полностью законный способ отслеживать количество уникальных и повторяющихся элементов, которые я добавляю в хэш-набор.

Когда я переформатирую его как if-then-else, он работает нормально.

Может ли кто-нибудь объяснить ошибку, и есть ли способ сделать это с помощью простого тернарного оператора?


person abelenky    schedule 06.04.2010    source источник
comment
Вместо этого я предпочитаю государственную сеть if. Фиктивная переменная назначения, которую предлагают некоторые ответы, просто добавляет путаницы.   -  person bruno conde    schedule 06.04.2010
comment
Также обратите внимание, что троичные числа обычно используются для выбора значения, а не действия. В вашем случае вы выбираете, увеличивать ли одно из двух значений. Таким образом, имеет больше смысла использовать if-else, поскольку вы выбираете действие.   -  person AaronLS    schedule 06.04.2010


Ответы (9)


Согласно сообщению об ошибке тернарный оператор не может использоваться в качестве оператора. Вам нужно будет сделать что-то вроде этого, чтобы превратить это в задание:

int dummy = groupUIDs.Add(uid)? unique++ : dupes++;

При этом я бы рекомендовал просто использовать if-then-else. Это не так запутанно, потому что не требует создания «волшебных» фиктивных переменных ...

person sth    schedule 06.04.2010
comment
Кажется, это исправляет. В C нет ничего плохого в автономном тернарном сервере, который ничего не делает. По-видимому, это не так в C #. Спасибо. - person abelenky; 06.04.2010
comment
Или используйте if вместо тернарного оператора вместо присвоения значения бесполезной переменной ради прохлады кода и ухудшения читабельности. - person ANeves thinks SE is evil; 06.04.2010
comment
полностью отформатированный оператор if занимает 8 строк с дополнительным уровнем отступа. Это кажется огромной тратой для такой простой операции. Как программист на C / C ++ мне очень комфортно работать с тернарным языком, и я не вижу никаких крутых факторов или того, что это ухудшает читабельность. - person abelenky; 06.04.2010
comment
Я предпочитаю открывать скобки в одной строке, но насчет количества строк вы абсолютно правы. Во что бы то ни стало, используйте тройную операцию и фиктивную фигуру, если вы так предпочитаете - пока это выбор, основанный на знаниях, это прекрасный выбор. :) - person ANeves thinks SE is evil; 06.04.2010
comment
@abelenky - я определенно понимаю, почему вы не назначали его ни на что, но в C # вы должны это сделать, хотя я бы хотел, чтобы вы этого не делали, это своего рода трата. У меня была такая же проблема несколько лет назад, и это меня действительно смутило ... Я бы не стал считать это фиктивной ошибкой или чем-то еще. - person Gabe; 06.04.2010
comment
if(groupsUIDs.Add(uid)) { unique++; } else { dupes++; } всего на 15 символов больше. - person AaronLS; 06.04.2010

Как указывали другие, условный оператор не является допустимым выражением оператора. (Допустимые выражения операторов - это присваивания, вызовы, приращения, декременты и конструкции.)

Однако здесь есть и стилистическая проблема. На мой взгляд, выражения должны быть полезны своими значениями, а операторы - своими побочными эффектами. Вы столкнулись с тем, что у вас есть выражение, которое полезно только из-за своего побочного эффекта, и это неприятный запах кода.

У вас есть побочный эффект, поэтому используйте условный оператор, а не условное выражение.

person Eric Lippert    schedule 06.04.2010
comment
Из уважения к @EricLippert я заменю его условным выражением if-else. Еще один шаг вверх по кривой обучения с C на C #. - person abelenky; 06.04.2010
comment
@abelenky: Я польщен, но, пожалуйста, не делай этого ради меня. Сделайте это ради будущих людей, которые должны поддерживать ваш код. :-) - person Eric Lippert; 07.04.2010

Вы не устанавливаете результат значения тернарного значения на что-либо, поэтому.

HashSet<long> groupUIDs = new HashSet<long>();
int count = groupUIDs.Add(uid)? unique++ : dupes++;
person Gabe    schedule 06.04.2010

Тернарный оператор не является утверждением. Таким образом, его нельзя использовать отдельно в инструкции - это эквивалент написания

"something that is not a statement";

Чтобы уточнить, вы должны удалить тернарный оператор и использовать if.

person ANeves thinks SE is evil    schedule 06.04.2010
comment
По крайней мере, в C и C ++ это совершенно верное утверждение (хотя и без побочных эффектов). По-видимому, это не так в C #. Оказывается, правильный ответ - иметь фиктивное назначение, как предложил @sth. - person abelenky; 06.04.2010
comment
Это отличное объяснение, потому что, если вы подумаете о том, как работает тернар, он оценивает одно значение, значение, которое выбирается из двух вариантов. Таким образом, после оценки это похоже на запись оператора, который является значением unique; (после увеличения) или dupes;, который будет чем-то вроде 12345;, который не был бы допустимым оператором, поскольку это просто единственное целое число. - person AaronLS; 06.04.2010
comment
@AaronLS: Во-первых, это будет значение unique PRIOR до увеличения, а не после. Во-вторых, во многих языках наличие единственного целого числа вполне допустимо. В этом отношении C # отличается. - person abelenky; 06.04.2010
comment
Между прочим, я понятия не имел, что одинокие целые числа могут быть операторами на других языках - а я знаю несколько. Один продолжает учиться. :) - person ANeves thinks SE is evil; 06.04.2010
comment
@abelenky Хороший пример порядка работы, я думал о постфиксе, но на самом деле сосредоточился на том факте, что он оценивается как целое число. Мы могли бы изучить все способы, которыми с этим справятся разные языки, например, 12345 не является полным утверждением на английском языке, но, поскольку вопрос помечен как C #, я думаю, было бы продуктивно сосредоточиться на этом;) - person AaronLS; 06.04.2010

Компилятор не жалуется Add, он жалуется на то, что ваше условное выражение не является полным утверждением.

Некоторые языки (например, JavaScript) позволяют использовать условное выражение для логики ветвления, как вы это сделали здесь, но C # требует, чтобы вы присваивали результат условного выражения переменной. Назначив результат выражения, вы сделали полный оператор, и компилятор доволен.

person Andrew Hare    schedule 06.04.2010
comment
Собственно, он жалуется на тернарный оператор. - person mmx; 06.04.2010
comment
@Andrew Разве это не будет считаться приращением, которое упоминается в сообщении об ошибке как допустимое выражение? - person AaronLS; 06.04.2010
comment
@abelenky: Нет ничего плохого в использовании здесь оператора ++. Проблема в том, что тернарное выражение само по себе не является утверждением: что-то вроде groupUIDs.Add(uid) ? 0 : 1; тоже не сработает. - person LukeH; 06.04.2010

Вам нужно использовать значение тернарного оператора для чего-то ...

HashSet<long> groupUIDs = new HashSet<long>();
int newCount = groupUIDs.Add(uid)? unique++ : dupes++;

или - используйте if

HashSet<long> groupUIDs = new HashSet<long>();
if (groupUIDs.Add(uid))
   unique++;
else
   dupes++;
person Brian Walker    schedule 06.04.2010

gmcalab и sr pt верны; тернарный оператор предназначен для того, чтобы дать вам результат, точно так же, как 1 + 1 дает вам 2. Вы не могли просто написать:

1 + 1;

Путаница здесь (я думаю) заключается в том, что вы думаете о тернарном операторе как о функции.

person Dan Tao    schedule 06.04.2010

описание тернарного оператора в языковая ссылка говорит, что

Если условие истинно, первое выражение оценивается и становится результатом; если false, второе выражение оценивается и становится результатом.

Похоже, что тернарный код можно использовать только в контексте присваивания, хотя в справочнике по языку это не указано. Вы не делаете задания по результату.

На мой взгляд, переписывание как if / else было бы более ясным.

person Andy Johnson    schedule 06.04.2010
comment
Это не обязательно должно быть присвоение - например, вы можете передать его другому методу. - person Jon Skeet; 06.04.2010
comment
Вы правы - я очень торопился, и мои формулировки были слишком расплывчатыми. - person Andy Johnson; 07.04.2010

Если это неприемлемо, почему ваша линия будет приемлемой? Просто используйте оператор if :-)

        bool b = false;
        b?callB():callA();
person Dested    schedule 06.04.2010