3 votes

Pourquoi dois-je utiliser le typecast d'un int dans une expression ternaire ?

Duplicata possible :
L'opérateur conditionnel ne peut pas effectuer de cast implicite ?

Je me suis retrouvé dans une situation particulière et je voudrais savoir pourquoi je dois le faire. J'utilise .NET 3.5.

Ça marche :

short foo;

if (isValid)
    foo = -1;
else
    foo = getFoo();

Cela ne fonctionne pas :

short foo;
foo = isValid ? -1 : getFoo();

Je dois faire le typage -1 :

short foo;
foo = isValid ? (short)-1 : getFoo();

Que fait l'expression ternaire différemment ? Elle considère que le -1 est un int qui doit être converti en short. Mais pourquoi ?

11voto

Eric Lippert Points 300275

Quelques trucs.

Tout d'abord, l'opérateur conditionnel est un opérateur ternaire, et non un opérateur tertiaire .

Deuxièmement, je constate que dans vos échantillons de code, les deux échantillons de code censés être équivalents ne le sont pas :

short foo;
if (isValid)
    foo = -1;
else
   getFoo();

n'est pas la même chose que

short foo = isValid ? (short)-1 : getFoo();

La première laisse foo non assigné si isValid est faux. La seconde assigne foo quelle que soit la valeur de isValid.

Je suppose que vous vouliez dire

short foo;
if (isValid)
    foo = -1;
else
    foo = getFoo();

et qu'en plus, getFoo() renvoie court.

La question est de savoir pourquoi la conversion dans l'opérateur conditionnel sans le cast de type est illégale mais dans la conséquence de l'instruction if est légale.

Il est légal dans l'instruction if parce que la section 6.1.9 de la spécification indique :

Une expression constante de type int peut être convertie en type sbyte, byte, short, ushort, uint ou ulong, à condition que la valeur de l'expression constante soit comprise dans la plage du type de destination.

-1 est une expression constante de type int qui est dans l'intervalle de short, elle peut donc être convertie en short implicitement.

Alors pourquoi la forme d'expression conditionnelle est-elle fausse ?

La première chose que nous devons établir clairement est la règle selon laquelle le type de l'expression conditionnelle est déterminé à partir de son contenu et non de son contexte . Le type de l'expression du côté droit d'une affectation ne dépend pas de ce à quoi elle est affectée ! Supposons que vous ayez

short M(short x){...}
int M(int x){...}

short y = M(-1);

Je ne pense pas que vous vous attendiez à ce que la résolution de surcharge dise "bien, je choisirais normalement M(int) parce que -1 est un int, mais non, je vais choisir M(short) à la place parce que sinon l'affectation ne fonctionnera pas". La résolution de surcharge ne sait rien sur où va le résultat . Son rôle est de déterminer quelle est la bonne surcharge en fonction des arguments donnés, et non en fonction du contexte de l'appel.

La détermination du type de l'expression conditionnelle fonctionne de la même manière. Nous ne regardons pas le type vers lequel elle va, nous regardons les types qui sont dans l'expression.

OK, nous avons donc établi que le fait que cette expression soit affectée à court n'est pas pertinent pour déterminer le type de l'expression. Mais cela laisse toujours la question "Pourquoi le type de l'expression conditionnelle est int plutôt que short ?"

C'est une très bonne question. Passons à la spécification.

Les deuxième et troisième opérandes, x et y, de l'opérateur ? : contrôlent le type de l'expression conditionnelle.

Si a le type X et y le type Y alors :

Si une conversion implicite existe de X à Y, mais pas de Y à X, alors Y est le type de l'expression conditionnelle.

Si une conversion implicite existe de Y à X, mais pas de X à Y, alors X est le type de l'expression conditionnelle.

Sinon, aucun type d'expression ne peut être déterminé, et une erreur de compilation se produit.

Dans ce cas, les opérandes ont tous deux un type. (Le verbiage à propos de "si x a un type..." est pour le cas où vous avez null ou un lambda ; ceux-ci n'ont pas de type). Le premier opérande est de type int, le second est de type short.

Une conversion implicite existe de short à int, mais pas de int à short. Par conséquent, le type de l'expression conditionnelle est int, qui ne peut pas être affecté à short.

On pourrait dire que cet algorithme n'est pas aussi bon qu'il pourrait l'être. Nous pourrions grandement compliquer l'algorithme pour traiter tous les cas où il y a deux types "candidats" possibles -- dans ce cas, int et short sont tous deux des candidats plausibles car les deux branches sont convertibles en int et en short. lorsqu'ils sont considérés comme des expressions spécifiques, plutôt que simplement comme ayant des types . Nous pourrions dire dans ce cas que le plus petit des deux types était le type préféré.

(Parfois, en C#, on dit que le plus général de deux types est le meilleur type, mais dans ce cas, vous voudriez que nous choisissions le plus spécifique. Le langage n'est pas cohérent dans cet aspect particulier de la conception, malheureusement ; personnellement, je préférerais que nous choisissions toujours le plus spécifique, mais il y a des scénarios d'inférence de type où cela serait un changement de rupture maintenant).

J'ai envisagé de le faire en 2006. Lors de la conception du comportement de LINQ dans les situations où il y a plusieurs types à choisir et où l'un d'eux doit être sélectionné comme "le meilleur", nous avons remarqué que l'opérateur conditionnel devait déjà résoudre ce problème et que, de plus, dans C# 2, il n'était pas réellement implémenté conformément à la spécification. Un long débat a eu lieu à ce sujet et nous avons fini par apporter quelques modifications mineures à la spécification de l'opérateur conditionnel afin de le rendre plus conforme à son comportement implémenté (et souhaité). Cependant, nous avons décidé de ne pas prendre la décision de modifier l'algorithme pour qu'il utilise le plus petit des deux types possibles, alors qu'il en existe plusieurs.

Pour quelques réflexions sur ce problème, voir mes posts de 2006 à ce sujet :

6voto

Kevin Points 57797

Parce que -1 par défaut est un nombre entier. Il est beaucoup plus sûr pour le compilateur de vous dire que vous devez lui dire explicitement ce qu'il doit faire, que pour le compilateur de faire une supposition sur ce que vous voulez faire.

Votre exemple est assez simple. Avec un peu de travail supplémentaire, le compilateur pourrait évidemment voir que vous voulez que -1 soit un court. Il y a tous les cas limites qui vont de pair avec la conversion implicite qui ne sont pas si simples cependant. Si vous ajoutez une règle pour que le compilateur fasse une supposition sur ce que vous voulez, vous devez l'appliquer à tous les cas et pas seulement à un, et c'est là que cela devient difficile.

À titre d'information, vous devriez consulter Eric Lippert blog comme je sais qu'il couvre pourquoi le compilateur ne fait pas de telles hypothèses.

1voto

SLaks Points 391154

Un opérateur conditionnel appliqué à un int et un short est de type int ; le compilateur ne déduira pas le type de l'expression à partir du type auquel vous l'assignez.

Vous ne pouvez pas lancer implicitement cette short à une expression int .

0voto

João Angelo Points 24422

L'opérateur conditionnel impose que les deux expressions de résultat possibles soient du même type. Dans ce cas, le côté gauche est un int et le côté droit est un short retourné par getPoo méthode. Puisqu'il est toujours sûr de convertir un short en un int le compilateur choisit que le résultat de l'opération sera un int .

Le résultat sera donc l'affectation d'un int à un short et c'est pourquoi vous devez explicitement le transformer en un court.

Si vous utilisez explicitement une approche if/else, vous assignerez un entier littéral à un court, ce qui permet au compilateur de vérifier que l'entier littéral est bien assigné à un court sans avoir besoin d'un cast explicite.

Pour une explication approfondie, consultez le site :

Les opérateurs de coulée n'obéissent pas à la loi distributive.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X