Подтвердить что ты не робот

Использование С# тройной с 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?)

Почему мне приходится записывать последние два случая, а не в двух первых случаях?

4b9b3361

Ответ 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;

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