Использование С# тройной с String.Equals
Это работает:
short value;
value = 10 > 4 ? 5 : 10;
Это работает:
short value;
value = "test" == "test" ? 5 : 10;
Это не работает:
short value;
string str = "test";
value = "test" == str ? 5 : 10;
Также это:
short value;
string str = "test";
value = "test".Equals(str) ? 5 : 10;
В последних двух случаях я получаю следующую ошибку:
Cannot implicitly convert type 'int' to 'short'.
An explicit conversion exists (are you missing a cast?)
Почему мне приходится записывать последние два случая, а не в двух первых случаях?
Ответы
Ответ 1
short value;
value = 10 > 4 ? 5 : 10; //1
value = "test" == "test" ? 5 : 10; //2
string str = "test";
value = "test" == str ? 5 : 10; //3
value = "test".Equals(str) ? 5 : 10; //4
Последние два тройных выражения (3,4) не могут быть разрешены константой во время компиляции. Таким образом, компилятор обрабатывает литералы 5
и 10
как int
, а тип всего тройного выражения - int
. Для преобразования из int
в short
требуется явное преобразование.
Первые два тернарных выражения (1,2) могут быть разрешены к константе во время компиляции. Постоянным значением является int
, но компилятор знает, что он соответствует short
, и поэтому не требует кастинга.
Для удовольствия попробуйте следующее:
value = "test" == "test" ? 5 : (int)short.MaxValue + 1;
Ответ 2
Вам нужно бросить, чтобы сделать два последних примера работы
value = (short)("test" == str ? 5 : 10);
Почему вам это не нужно в первых двух?
Потому что первые два являются константами времени компиляции. Компилятор может перевести 10 > 4 ? 5 : 10
в true ? 5 : 10
, а затем просто 5
Итак, когда вы пишете
value = 10 > 4 ? 5 : 10;
Он эффективно аналогичен
value = 5;
который компилируется, потому что компилятору разрешено неявно приводить константы, если они находятся в допустимом диапазоне.
И наоборот, "test" == str ? 5 : 10;
не является постоянной времени компиляции, поэтому компилятору не разрешается использовать его. Вам нужно сделать явный листинг yoursef.
Ответ 3
Это, конечно, определено Спецификацией языка С#.
Главное, что нужно знать, это два типа преобразований от int
до short
. Один из них - это явное преобразование, которое всегда применяется, но для которого требуется написать (short)
явно перед выражением int
. Другой - это неявное преобразование константных выражений, которое применяется только тогда, когда (a) int
выражение является константой времени компиляции и (b) значение этого выражения времени компиляции находится в диапазоне от short
, то есть от -32768
до 32767
.
Литерал как 5
, 10
или 4
имеет тип int
в С# (который идет для любого целочисленного литерала, который находится между -2147483648
и 2147483647
и не сопровождается символом L
, U
или тому подобное). Поэтому, если мы посмотрим на правые части всех ваших назначений, они явно выражают int
, а не short
.
В случае 10 > 4 ? 5 : 10
, поскольку 10
и 4
являются константами времени компиляции, это то же самое, что и true ? 5 : 10
, потому что оператор >
между int
встроен и приведет к константа, когда операнды являются константами. И таким же образом true ? 5 : 10
дает 5
, потому что все три операнда являются константами, а ?:
классифицируется как константа в этом случае. Поэтому он действительно говорит:
short value = 5;
где "5
" является константой времени компиляции. Следовательно, он проверяется во время компиляции, если int
5
находится в пределах диапазона (это не имеет значения с 10
, оно может быть 999999
), и, поскольку это так, подразумевается постоянное выражение применяется конверсия, и это является законным.
Обратите внимание, что вы можете сделать то же самое:
const int huge = 10;
const int tiny = 4;
const int significant = 5;
const int unimporatnt = 10;
short value;
value = huge > tiny ? significant : unimportant;
пока все операнды являются const
переменными (каламбур?).
Теперь, если мне удастся объяснить объяснение, вы также будете знать, что препятствие, препятствующее работе value = "test" == str ? 5 : 10;
, заключается в том, что вы не отметили локальный str
как const
. Сделайте это, и это будет разрешено.
С вызовом Equals
все немного хуже. Результат вызова Equals
никогда не считается константой времени компиляции (и я не думаю, что он "оптимизирован", например "same".Equals("same")
фактически вызовет метод во время выполнения). То же самое произойдет с (10).Equals(4)
или (10).CompareTo(4) > 0
и т.д., Поэтому строки не являются особыми в этом отношении.
Скорее всего, вы уже знаете, что когда
short value = cond ? 5 : 10;
не разрешено, потому что cond
не является константой времени компиляции, вы просто используете явное преобразование, поэтому пишите:
short value = cond ? (short)5 : (short)10;
или
short value = (short)(cond ? 5 : 10);
Технически они не идентичны, поскольку первый не имеет суживающего преобразования во время выполнения (выражения (short)5
и (short)10
являются литералами типа short
), в то время как последний должен преобразовать int
до short
во время выполнения (что, конечно, дешевле, чем невероятно дешево).
Другие (не удаленные!) ответы верны, это просто информация о бонусах.
Ответ 4
Дело в том, что 10 > 4 ? 5 : 10;
фактически преобразуется в константу во время компиляции до того, как требуется какое-либо разлитие типов. Это означает, что компилятор понял, что оператор поворота фактически может быть сведен к константе даже до того, как для компиляции потребуется какой-либо неявный тип. Иными словами, это выражение такое же, как:
value = 5;
В двух последних утверждениях это неверно, поскольку вы используете переменную для хранения значений для вас, а не константы. Компилятор не проверяет фактическое значение переменной, чтобы увидеть, может ли оно уменьшить выражение до константы. Так что вам действительно нужно кастинг.