Условный оператор не может действовать неявно?
Я немного взволнован этой маленькой чертой С#:
Данные переменные:
Boolean aBoolValue;
Byte aByteValue;
Следующие компиляции:
if (aBoolValue)
aByteValue = 1;
else
aByteValue = 0;
Но это не будет:
aByteValue = aBoolValue ? 1 : 0;
Ошибка говорит: "Невозможно неявно преобразовать тип" int "в" byte ".
И, конечно же, это чудовище будет компилироваться:
aByteValue = aBoolValue ? (byte)1 : (byte)0;
Что здесь происходит?
EDIT:
Использование VS2008, С# 3.5
Ответы
Ответ 1
Это довольно часто задаваемый вопрос.
В С# мы почти всегда рассуждаем изнутри наружу. Когда вы видите
x = y;
мы выясним, что такое тип x, каков тип y, и является ли тип y равным присваиванию, совместимому с x. Но мы не используем тот факт, что мы знаем, что такое тип x, когда мы разрабатываем тип 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). Поскольку он не является константой, вы не можете назначить его байту; компилятор ссылается исключительно на типы, а не на значения, когда результат не является константой.
Исключением для всех этих правил являются лямбда-выражения, где информация о типе передается из контекста в лямбда. Правильная логика была очень сложной.
Ответ 2
Я использую VS 2005, потому что и я могу воспроизвести, для bool и 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);
Итак, да, кажется, что тернарный оператор заставляет константы "фиксировать" их типы как ints и отключать неявное преобразование типа, которое вы в противном случае получали бы от констант, которые соответствуют меньшему типу.
Ответ 3
У меня, возможно, нет большого ответа для вас, но если вы сделаете это во многих местах, вы можете объявить:
private static readonly Byte valueZero = (byte)0;
private static readonly Byte valueOne = (byte)1;
и только эти переменные. Вы можете избежать использования const
, если оно локально для проекта.
EDIT: с помощью readonly
не имеет смысла - они никогда не должны меняться.