Почему я могу передать 1 как короткую, а не переменную int i?

146

Почему первая и вторая запись работает, но не последняя? Есть ли способ, которым я могу разрешить все 3 из них и определить, было ли это 1, (int) 1 или я передал? И действительно, почему один разрешен, но последний? Второе позволение, но не последнее действительно поражает меня.

Демо, чтобы показать ошибку компиляции

using System;
class Program
{
    public static void Write(short v) { }
    static void Main(string[] args)
    {
        Write(1);//ok
        Write((int)1);//ok
        int i=1;
        Write(i);//error!?
    }
}
CodesInChaos
источник
2
Я тоже озадачен этим, мне часто приходится приводить целые числа к коротким в вызовах функций, хотя они должны быть кастуемыми ...
Матье Думулин
2
@MathieuDumoulin они кастуемы, поэтому вы можете их кастовать. Но это преобразование с потерями (есть много целых, которые не помещаются в коротких), поэтому неявное приведение невозможно, поэтому вы должны писать (short) i.
Авель

Ответы:

186

Первые два являются константными выражениями, последнее - нет.

Спецификация C # допускает неявное преобразование из int в короткое для констант, но не для других выражений. Это разумное правило, поскольку для констант компилятор может гарантировать, что значение соответствует целевому типу, но не может для нормальных выражений.

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

6.1.8 Неявные преобразования константных выражений

Неявное преобразование константного выражения допускает следующие преобразования:

  • Постоянное выражение (§7.18) типа intможет быть преобразована к типу sbyte, byte, short, ushort, uint, или ulong, при условии , что величина постоянной экспрессии находится в пределах диапазона от типа назначения.
  • Постоянное выражение- типа longможет быть преобразовано в тип ulong, при условии , что значение константы-выражениях не является отрицательным.

(Цитируется из C # Language Specification Version 3.0)

CodesInChaos
источник
67

Не существует неявного преобразования из intв shortиз-за возможности усечения. Однако константное выражение может рассматриваться компилятором как целевое .

1? Не проблема: это явно допустимое shortзначение. i? Не так много - это может быть какое-то значение> short.MaxValueнапример, и компилятор не может проверить это в общем случае.

Конрад Рудольф
источник
Так что ... не важно, насколько я откровенен ...> _ <. Есть ли у вас какие-либо идеи, если я могу определить, был ли передан litereal или переменная int?
@ acidzombie24 Вы не можете. Но почему вы хотите это сделать?
Адам Хоулдсворт
@ acidzombie24 Не думаю, что ты сможешь это обнаружить. Однако вы можете использовать аргумент шаблона, а затем использовать отражение, чтобы получить его тип.
Конрад Рудольф
3
@ acidzombie24 Невозможно передать литерал во время выполнения. Таким образом, вы можете просто использовать свои глаза, чтобы проверить во время компиляции.
Джастин
1
@ acidzombie24 В таком случае, будет ли вариант принять аргумент как Expression<Func<int>>? Затем вы можете передать () => 1или () => iи внутри функции вы можете проверить, содержит ли переданная сущность захваченную переменную или постоянное значение.
Конрад Рудольф
8

int литерал может быть неявно преобразован в short. В то время как:

Вы не можете неявным образом преобразовать нелитеральные числовые типы с большим объемом памяти в короткие

Итак, первые два работают, потому что неявное преобразование литералов разрешено.

Damien_The_Unbeliever
источник
3
Ваш ответ немного неправильный. Вы не должны использовать буквальное, но константное выражение . В частности, второй пример не является буквальным .
CodesInChaos
6

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

Редактировать: Кто-то избил меня до этого!

Джастин
источник
3

Потому что не будет никакого неявного преобразования между Нелитеральным типом в короткий размер большего размера.

Неявное преобразование возможно только для константного выражения.

public static void Write(short v) { }

Где, когда вы передаете integerзначение в качестве аргументаshort

int i=1;
Write(i);  //Which is Nonliteral here
Вишал Сутар
источник
3

Компилятор сказал вам, почему код не работает:

cannot convert `int' expression to type `short'

Итак, вот вопрос, который вы должны задать: почему это преобразование не удается? Я гуглил "c # convert int short" и оказался на странице MS C # для shortключевого слова:

http://msdn.microsoft.com/en-us/library/ybs77ex4(v=vs.71).aspx

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

Write((short)i)
Исаак Рабинович
источник
0

Преобразование из int -> short может привести к усечению данных. Поэтому.

ak1238
источник