Почему?: Вызывает ошибку преобразования, а if-else - нет?

Сделав некоторые изменения в коде, я использую следующую строку:

uint a = b == c ? 0 : 1;

Visual Studio показывает мне эту ошибку:

Невозможно неявно преобразовать тип 'int' в 'uint'. Явное преобразование существует (вы пропускаете листинг?)

Но если я использую код:

uint a; 

if (b == c) 
    a = 0; 
else 
    a = 1;

Он работает правильно, без каких-либо ошибок или предупреждений. Почему?

Ответ 1

Почему я не могу использовать uint a = b == c ? 0 : 1;?

Тип выражения b == c ? 0 : 1 равен int. Как показано в в этой таблице, нет никакого неявного преобразования из int в uint, поэтому это не разрешено.

Почему я могу использовать a = 0?

Потому что существует специальная обработка числовых типов, когда значение является постоянным выражением.

Из раздела 6.1.9 спецификации С#:

  • Константное выражение типа int может быть преобразовано в тип sbyte, byte, short, ushort, uint или ulong, если значение константного выражения находится в пределах диапазона типа назначения.

  • Постоянное выражение типа long может быть преобразовано в тип ulong, если значение константного выражения не является отрицательным.

Как указано в первой марке a = 0 и a = 1, оба разрешены, потому что 0 и 1 являются константными выражениями и являются действительными значениями uint. В основном это сводится к тому, что компилятор может легко определить во время компиляции, что эти преобразования действительны, поэтому он позволяет им.

Кстати, если часть вашего первого примера b == c была изменена на константное выражение (например, true), тогда все условное выражение оператора будет постоянным выражением, и код будет компилироваться.

Ответ 2

Если b==c были постоянным выражением, тогда весь условный оператор считался бы константным выражением, и поэтому тогда правило, позволяющее преобразовывать константные выражения типа int в другое int типы будут применяться и будут компилироваться.

Очевидно, что b==c не является постоянным выражением, поэтому результат условного оператора не может быть известен до выполнения, поэтому исключение, допускающее неявное преобразование int в uint (для постоянных выражений), не применяется.

В вашем варианте if/else оба фактических назначения являются постоянными выражениями.

Ответ 3

Вы должны использовать литералы, чтобы ваш код работал правильно:

uint a = b == c ? 0U : 1U;