Чому я можу пропустити 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!?
    }
}

2
Мені теж це заважає, мені часто доводиться вводити вкладиші для коротких функціональних викликів, хоча вони повинні бути передаваними ...
Mathieu Dumoulin

2
@MathieuDumoulin вони кастетні, тому ви можете їх віддати. Але це конвертація втрат (є багато входів, які не підходять за короткий час), тому неявна передача неможлива, тому вам доведеться писати (short) i.
Абель

Відповіді:


186

Перші два - це постійні вирази, останні - ні.

Специфікація C # дозволяє неявну конверсію з int в short для констант, але не для інших виразів. Це розумне правило, оскільки для констант компілятор може гарантувати, що значення вписується в цільовий тип, але воно не може для нормальних виразів.

Це правило відповідає принципу, що неявна конверсія повинна бути без втрат.

6.1.8 Неявні перетворення постійних виразів

Неявна конверсія постійного вираження дозволяє проводити такі перетворення:

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

(Цитується з мовлення C # Версія 3.0)


67

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

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


Тож ... не має значення, наскільки явний я ...> _ <. Чи маєте ви якусь ідею, чи можу я виявити, чи було передано літеральне чи змінну int?

@ acidzombie24 Ви не можете. Але чому б ти хотів це зробити?
Адам Холдсворт

@ acidzombie24 Я не думаю, що ти можеш це виявити. Однак ви можете використовувати аргумент шаблону, а потім використовувати відображення, щоб отримати його тип.
Конрад Рудольф

3
@ acidzombie24 Ніякого способу неможливо було передавати під час виконання. Таким чином, ви можете просто використовувати очі, щоб перевірити час компіляції.
Джастін

1
@ acidzombie24 У такому випадку було б варіантом прийняти аргумент як an Expression<Func<int>>? Тоді ви можете передати функцію () => 1або в ній, () => iі ви зможете перевірити, чи містить передане об'єкт захоплену змінну чи постійне значення.
Конрад Рудольф

8

int літерал може бути неявно перетворений в short. При цьому:

Не можна неявно перетворювати нелітеральні числові типи більшого розміру пам’яті в короткі

Отже, перші два працюють тому, що допускається неявна конверсія літералів.


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 може призвести до обрізання даних. Ось чому.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.