Вопрос по conditional-operator, c#, implicit-cast, types – Условный оператор не может быть приведен неявно?

58

Я немного озадачен этой маленькой причудой C #:

Данные переменные:

Boolean aBoolValue;
Byte aByteValue;

Следующие компиляции:

if (aBoolValue) 
    aByteValue = 1; 
else 
    aByteValue = 0;

Но это не будет

aByteValue = aBoolValue ? 1 : 0;

Ошибка говорит: «Невозможно неявно преобразовать тип« int »в« byte ».»

И, конечно, это чудовище скомпилирует:

aByteValue = aBoolValue ? (byte)1 : (byte)0;

Что тут происходит?

РЕДАКТИРОВАТЬ:

Использование VS2008, C # 3.5

Ваш Ответ

3   ответа
7

Возможно, у меня нет хорошего ответа для вас, но если вы делаете это во многих местах, вы можете заявить:

private static readonly Byte valueZero = (byte)0;
private static readonly Byte valueOne = (byte)1;

и только эти переменные. Вы можете сойти с рук с помощьюconst если это локально для проекта.

РЕДАКТИРОВАТЬ: с помощьюreadonly не имеет смысла - это никогда не должно измениться.

Я уверен, что это была просто опечатка, но вы объявили одну и ту же переменную дважды. Cory Charlton
@ Хэмиш: Я понимаю, что ты имеешь в виду. Я мог бы использовать const, но это обходной путь. Это, конечно, не заслуживает того голосования, которое вы получили. MPelletier
67

В C # мы почти всегда рассуждаем изнутри наружу. Когда ты видишь

x = y;

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

Это потому, что может быть более одного x:

void M(int x) { }
void M(string x) { }
...
M(y); // y is assigned to either int x or string x depending on the type of y

Мынеобходимость чтобы иметь возможность определить тип выражениябез зная, что это назначается. Тип информационных потоковиз выражения, а нев выражение.

Чтобы определить тип условного выражения, мы определяем тип следствия и альтернативные выражения, выбираем более общий из двух типов, и это становится типом условного выражения. Итак, в вашем примере тип условного выражения - «int», и он не является константой (если только выражение условия не является константой true или константой false). Поскольку это не константа, вы не можете присвоить ее байту; компилятор рассуждает исключительно из типов, а не из значений, когда результат не является константой.

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

var x = y отличается отint x = y и следует относиться по-разному. В первом случае я прошу компилятор выяснить это, во втором я говорю то, что ожидаю. И, как говорит @devuxer, большинство разработчиков ожидают?: работать какif-else. Thomas Eyde
Мой мозг взорвался. Спасибо, сэр, это одна часть просвещения и две части разочаровывают. Один, потому что он не может работать так, как онказаться работать, и два, потому что имеет смысл, что это не может работать таким образом. Так что ... это константы! MPelletier
@John: я немного расскажу об этих вопросах здесь:blogs.msdn.com/ericlippert/archive/2006/05/24/... Eric Lippert
@Eric Lippert, я попытался прокомментировать вашу запись в блоге, но я не уверен, что это заняло, поэтому я спрошу здесь: Вместо того, чтобы пытаться самостоятельно разрешать типы, почему компилятор не преобразует просто все троичное выражение в эквивалентное «подробное выражение» (в этом случаеbyte aByteValue; if (aBoolValue) aByteValue = 1; else aByteValue = 0;)? Есть ли какие-то ошибки, которые сделали бы это нежизнеспособным? Или это философская вещь (например, «если оно выглядит как выражение, оно должно оцениваться как одно»)? Я думаю, что большинство программистов изначально ожидают, что троичный код будет работать точно так же, как если бы еще. devuxer
11

Boolean, но не для истинного

 bool abool = true;
 Boolean aboolean = true;
 Byte by1 = (abool ? 1 : 2);    //Cannot implicitly convert type 'int' to 'byte'
 Byte by2 = (aboolean ? 1 : 2); //Cannot implicitly convert type 'int' to 'byte'
 Byte by3 = (true ? 1 : 2);     //Warning: unreachable code ;)

Самый простой обходной путь, кажется, этот бросок

 Byte by1 = (Byte)(aboolean ? 1 : 2);

Так что, да, похоже, что троичный оператор заставляет константы «фиксировать» свои типы как целочисленные и отключать неявное преобразование типов, которое вы иначе получили бы от констант, которые вписываются в меньший тип.

@ Джон Ноллер: вы можете найти ссылку? Fitzchak Yitzchaki
Я думаю, что Эрик Липперт, возможно, уже обсуждал причину этого в своем блоге. John Knoeller
@ Джон: круто :-) Fitzchak Yitzchaki
Ваше объяснение имеет смысл. Но почему бы константы не исправить в этом случае? И вдвойне любопытно с открытием Менди. Кто-то в Microsoft должен знать, и, возможно, нужно будет решительно спорить с ... MPelletier

Похожие вопросы