Pourquoi puis-je passer 1 comme une variable courte, mais pas la variable int i?

146

Pourquoi la première et la deuxième écriture fonctionnent-elles mais pas la dernière? Existe-t-il un moyen de les autoriser tous les 3 et de détecter si c'était 1, (int) 1 ou si je suis passé? Et vraiment pourquoi est-il permis mais le dernier? Le second étant autorisé mais pas le dernier me souffle vraiment.

Démo pour afficher l'erreur de compilation

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
la source
2
Je suis moi aussi perplexe, je dois souvent lancer des appels de fonction courts, même s'ils devraient être castables ...
Mathieu Dumoulin
2
@MathieuDumoulin ils sont castables, c'est pourquoi vous pouvez les lancer. Mais c'est une conversion avec perte (il y a beaucoup d'entiers qui ne rentrent pas dans un court), donc le cast implicite n'est pas possible, c'est pourquoi vous devez écrire (short) i.
Abel

Réponses:

186

Les deux premiers sont des expressions constantes, le dernier ne l'est pas.

La spécification C # permet une conversion implicite de int en short pour les constantes, mais pas pour les autres expressions. C'est une règle raisonnable, car pour les constantes, le compilateur peut garantir que la valeur correspond au type cible, mais il ne le peut pas pour les expressions normales.

Cette règle est conforme à la directive selon laquelle les conversions implicites doivent être sans perte.

6.1.8 Conversions d'expressions constantes implicites

Une conversion d'expression constante implicite permet les conversions suivantes:

  • Une expression de constante (§7.18) de type intpeut être converti au type sbyte, byte, short, ushort, uint, ou ulong, à condition que la valeur de l' expression de la constante se situe dans la plage du type de destination.
  • Une expression constante de type longpeut être convertie en type ulong, à condition que la valeur de l' expression constante ne soit pas négative.

(Cité de C # Language Specification Version 3.0)

CodesInChaos
la source
67

Il n'y a pas de conversion implicite de intà en shortraison de la possibilité de troncature. Cependant, une expression constante peut être traitée comme étant du type cible par le compilateur .

1? Pas de problème: c'est clairement une shortvaleur valide . i? Pas tellement - cela pourrait être une valeur> short.MaxValuepar exemple, et le compilateur ne peut pas vérifier cela dans le cas général.

Konrad Rudolph
la source
Alors ... peu importe à quel point je suis explicite ...> _ <. Avez-vous une idée si je peux détecter si un littéral a été passé ou une variable int?
@ acidzombie24 Vous ne pouvez pas. Mais pourquoi tu veux faire ça?
Adam Houldsworth du
@ acidzombie24 Je ne pense pas que vous puissiez le détecter. Vous pouvez cependant utiliser un argument de modèle, puis utiliser la réflexion pour obtenir son type.
Konrad Rudolph du
3
@ acidzombie24 Il n'y a aucun moyen de passer un littéral pendant l'exécution. Vous pouvez donc simplement utiliser vos yeux pour vérifier au moment de la compilation.
Justin du
1
@ acidzombie24 Dans ce cas, serait-il possible d'accepter l'argument comme un Expression<Func<int>>? Ensuite, vous pouvez passer () => 1ou () => iet à l'intérieur de la fonction, vous pouvez vérifier si l'entité transmise contient une variable capturée ou une valeur constante.
Konrad Rudolph du
8

un int littéral peut être implicitement converti en short. Tandis que:

Vous ne pouvez pas convertir implicitement des types numériques non littéraux de plus grande taille de stockage en courts

Ainsi, les deux premiers fonctionnent car la conversion implicite de littéraux est autorisée.

Damien_The_Unbeliever
la source
3
Votre réponse est légèrement fausse. Vous ne devriez pas utiliser d' expression littérale mais constante . En particulier, le deuxième exemple n'est pas un littéral .
CodesInChaos du
6

Je crois que c'est parce que vous passez un littéral / constant dans les deux premiers, mais il n'y a pas de conversion de type automatique lors du passage d'un entier dans le troisième.

Edit: Quelqu'un m'a battu!

Justin
la source
3

Parce qu'il n'y aura aucune conversion implicite entre le type non littéral en short de plus grande taille.

La conversion implicite n'est possible que pour l'expression constante.

public static void Write(short v) { }

Où lorsque vous passez la integervaleur comme argument àshort

int i=1;
Write(i);  //Which is Nonliteral here
Vishal Suthar
la source
3

Le compilateur vous a expliqué pourquoi le code échoue:

cannot convert `int' expression to type `short'

Alors, voici la question que vous devriez vous poser: pourquoi cette conversion échoue-t-elle? J'ai googlé "c # convert int short" et je me suis retrouvé sur la page MS C # pour le shortmot clé:

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

Comme l'indique cette page, les transtypages implicites d'un type de données plus grand vers shortne sont autorisés que pour les littéraux. Le compilateur peut dire quand un littéral est hors de portée, mais pas autrement, il doit donc être assuré que vous avez évité une erreur hors de portée dans la logique de votre programme. Cette assurance est fournie par un casting.

Write((short)i)
Isaac Rabinovitch
la source
0

La conversion de int -> short peut entraîner une troncature des données. C'est pourquoi.

ak1238
la source