Dlaczego mogę przekazać 1 jako krótką, ale nie zmienną int i?

146

Dlaczego pierwsza i druga funkcja Write działają, a nie ostatnia? Czy istnieje sposób, w jaki mogę zezwolić na wszystkie 3 z nich i wykryć, czy był to 1, (int) 1, czy też przeszedłem? I naprawdę, dlaczego jeden jest dozwolony, ale ostatni? Drugie pozwolenie, ale nie ostatnie, naprawdę zaskakuje mnie.

Demo pokazujące błąd kompilacji

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
źródło
2
Ja też jestem zakłopotany przez to, że często mają do wskazówki rzutować na krótki w wywołań funkcji, chociaż powinny być one rzutować ...
Mathieu Dumoulin
2
@MathieuDumoulin można je rzucać, dlatego możesz je rzucać. Ale jest to konwersja bez strat (jest wiele int, które nie mieszczą się w short), więc niejawne rzutowanie nie jest możliwe, dlatego musisz pisać (short) i.
Abel,

Odpowiedzi:

186

Pierwsze dwa to wyrażenia stałe, a ostatnie nie.

Specyfikacja C # umożliwia niejawną konwersję z int do short dla stałych, ale nie dla innych wyrażeń. Jest to rozsądna zasada, ponieważ w przypadku stałych kompilator może zapewnić, że wartość pasuje do typu docelowego, ale nie może tego zrobić w przypadku zwykłych wyrażeń.

Zasada ta jest zgodna z wytyczną, zgodnie z którą niejawne konwersje powinny być bezstratne.

6.1.8 Niejawne konwersje wyrażeń stałych

Niejawna konwersja wyrażenia stałego zezwala na następujące konwersje:

  • Stałej ekspresji (§7.18) typu intmoże być przekształcany do typu sbyte, byte, short, ushort, uint, i ulongpod warunkiem, że wartość stałej ekspresji jest w zakresie od rodzaju docelowej.
  • Stałej ekspresji typu longmożna przekształcić rodzaju ulong, pod warunkiem, że wartość stałej ekspresji nie jest ujemny.

(Cytat z specyfikacji języka C # w wersji 3.0)

CodesInChaos
źródło
67

Ze względu na możliwość obcięcia nie ma niejawnej konwersji z intna short. Jednak wyrażenie stałe może być traktowane jako typ docelowy przez kompilator .

1? Nie ma problemu: to oczywiście ważna shortwartość. i? Nie tak bardzo - short.MaxValuena przykład może to być jakaś wartość , a kompilator nie może tego sprawdzić w ogólnym przypadku.

Konrad Rudolph
źródło
Więc ... nie ma znaczenia, jak wyraźna jestem ...> _ <. Czy masz pojęcie, czy mogę wykryć, czy przekazano litereal lub zmienną int?
@ acidzombie24 Nie możesz. Ale dlaczego chcesz to zrobić?
Adam Houldsworth,
@ acidzombie24 Myślę, że nie możesz tego wykryć. Państwo może jednak skorzystać z szablonu argumentu, a następnie użyć refleksji uzyskać w swoim rodzaju.
Konrad Rudolph,
3
@ acidzombie24 Nie ma możliwości przekazania literału w czasie wykonywania. Możesz więc po prostu użyć oczu, aby sprawdzić w czasie kompilacji.
Justin,
1
@ acidzombie24 Czy w takim przypadku byłoby opcją zaakceptowanie argumentu jako Expression<Func<int>>? Następnie możesz przekazać () => 1lub () => iwewnątrz funkcji sprawdzić, czy przekazana jednostka zawiera przechwyconą zmienną lub stałą wartość.
Konrad Rudolph
8

int dosłownym można niejawnie przekształca się short. Natomiast:

Nie można niejawnie konwertować nieliteralnych typów liczbowych o większym rozmiarze magazynu na krótki

Tak więc pierwsze dwa działają, ponieważ niejawna konwersja literałów jest dozwolona.

Damien_The_Unbeliever
źródło
3
Twoja odpowiedź jest trochę błędna. Nie powinieneś używać dosłownego, ale stałego wyrażenia . W szczególności drugi przykład nie jest dosłowny .
CodesInChaos
6

Uważam, że dzieje się tak, ponieważ w pierwszych dwóch podajesz literał / stałą, ale nie ma automatycznej konwersji typu podczas przekazywania liczby całkowitej w trzeciej.

Edycja: Ktoś mnie pokonał!

Justin
źródło
3

Ponieważ nie będzie żadnej niejawnej konwersji między Nonliteral typem o większym rozmiarze.

Niejawna konwersja jest możliwa tylko w przypadku wyrażenia stałego.

public static void Write(short v) { }

Gdzie jak przekazujesz integerwartość jako argument doshort

int i=1;
Write(i);  //Which is Nonliteral here
Vishal Suthar
źródło
3

Kompilator powiedział ci, dlaczego kod nie działa:

cannot convert `int' expression to type `short'

Oto pytanie, które powinieneś zadać: dlaczego ta konwersja się nie udaje? Wyszukałem w Google „c # convert int short” i znalazłem się na stronie MS C # dla shortsłowa kluczowego:

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

Jak mówi ta strona, niejawne rzutowania z większego typu danych na shortsą dozwolone tylko dla literałów. Kompilator może stwierdzić, kiedy literał jest poza zakresem, ale nie inaczej, więc potrzebuje zapewnienia, że ​​uniknąłeś błędu poza zakresem w logice programu. To zapewnienie zapewnia obsada.

Write((short)i)
Izaak Rabinowicz
źródło
0

Konwersja z int -> short może spowodować obcięcie danych. Dlatego.

ak1238
źródło