Perché posso passare 1 come breve, ma non la variabile int i?


146

Perché la prima e la seconda scrittura funzionano ma non l'ultima? Esiste un modo per consentirli tutti e 3 e rilevare se fosse 1, (int) 1 o se sono passato? E davvero perché uno è permesso ma l'ultimo? Il secondo è permesso ma non l'ultimo mi fa davvero impazzire.

Demo per mostrare l'errore di compilazione

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
Anch'io sono sconcertato da questo, spesso devo lanciare inserti per abbreviare le chiamate di funzione, anche se dovrebbero essere calcolabili ...
Mathieu Dumoulin,

2
@MathieuDumoulin sono calcabili, ecco perché puoi lanciarli. Ma è una conversione senza perdite (ci sono molti ints che non rientrano in un breve), quindi il cast implicito non è possibile, ecco perché devi scrivere (short) i.
Abel,

Risposte:


186

I primi due sono espressioni costanti, l'ultimo no.

La specifica C # consente una conversione implicita da int a short per le costanti, ma non per altre espressioni. Questa è una regola ragionevole, poiché per le costanti il ​​compilatore può garantire che il valore si adatti al tipo di destinazione, ma non per le espressioni normali.

Questa regola è in linea con le linee guida secondo cui le conversioni implicite dovrebbero essere senza perdita.

6.1.8 Conversioni implicite di espressioni costanti

Una conversione di espressione costante implicita consente le seguenti conversioni:

  • Un'espressione-costante (§7.18) di tipo intpuò essere convertito nel tipo sbyte, byte, short, ushort, uint, oppure ulong, a condizione che il valore della costante espressione rientra nell'intervallo del tipo di destinazione.
  • Una costante-espressione di tipo longpuò essere convertito nel tipo ulong, a condizione che il valore della costante espressione non è negativo.

(Citato da C # Language Specification Versione 3.0)


67

Non vi è alcuna conversione implicita da inta shortcausa della possibilità di troncamento. Tuttavia, un'espressione costante può essere trattata come di tipo target dal compilatore .

1? Non è un problema: è chiaramente un shortvalore valido . i? Non tanto - potrebbe essere un valore> short.MaxValueper esempio, e il compilatore non può verificarlo nel caso generale.


Quindi ... non importa quanto sono esplicito ...> _ <. Hai idea di poter rilevare se è stato superato un valore letterale o una variabile int?

@ acidzombie24 Non puoi. Ma perché dovresti farlo?
Adam Houldsworth l'

@ acidzombie24 Non credo che tu possa rilevarlo. È possibile comunque usare un argomento modello e quindi utilizzare la riflessione per arrivare al suo tipo.
Konrad Rudolph,

3
@ acidzombie24 Non è possibile in alcun modo passare un valore letterale durante il runtime. Quindi puoi semplicemente usare gli occhi per controllare al momento della compilazione.
Giustino,

1
@ acidzombie24 In tal caso, sarebbe un'opzione accettare l'argomento come Expression<Func<int>>? Quindi è possibile passare () => 1o () => ie all'interno della funzione è possibile verificare se l'entità passata conteneva una variabile acquisita o un valore costante.
Konrad Rudolph,

8

un int letterale può essere implicitamente convertito in short. Mentre:

Non è possibile convertire in modo implicito tipi numerici non letterali di dimensioni di archiviazione più grandi in brevi

Quindi, i primi due funzionano perché è consentita la conversione implicita di valori letterali.


3
La tua risposta è leggermente sbagliata Non dovresti usare un'espressione letterale ma costante . In particolare il secondo esempio non è letterale .
CodesInChaos,

6

Credo che sia perché stai passando una letterale / costante nei primi due, ma non c'è una conversione automatica del tipo quando passi un numero intero nel terzo.

Modifica: qualcuno mi ha battuto!


3

Perché non ci sarà alcuna conversione implicita tra tipo non letterale in short di dimensioni maggiori.

La conversione implicita è possibile solo per l'espressione costante.

public static void Write(short v) { }

Dove stai passando integervalore come argomentoshort

int i=1;
Write(i);  //Which is Nonliteral here

3

Il compilatore ti ha spiegato perché il codice fallisce:

cannot convert `int' expression to type `short'

Quindi, ecco la domanda che dovresti porre: perché questa conversione fallisce? Ho cercato su Google "c # convert int short" e sono finito sulla pagina MS C # per la shortparola chiave:

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

Come dice questa pagina, i cast impliciti da un tipo di dati più grande shortsono consentiti solo per i letterali. Il compilatore può dire quando un valore letterale è fuori portata, ma non diversamente, quindi ha bisogno di rassicurazione che hai evitato un errore fuori portata nella logica del tuo programma. Questa rassicurazione è fornita da un cast.

Write((short)i)

0

La conversione da int -> short potrebbe comportare il troncamento dei dati. Ecco perchè.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.