Partager via


Expression conditionnelle de type cible

Remarque

Cet article est une spécification de fonctionnalité. La spécification sert de document de conception pour la fonctionnalité. Elle inclut les changements de spécification proposés, ainsi que les informations nécessaires à la conception et au développement de la fonctionnalité. Ces articles sont publiés jusqu'à ce que les changements proposés soient finalisés et incorporés dans la spécification ECMA actuelle.

Il peut y avoir des différences entre la spécification de la fonctionnalité et l'implémentation réalisée. Ces différences sont consignées dans les notes pertinentes de la réunion de conception linguistique (LDM).

Pour en savoir plus sur le processus d'adoption des speclets de fonctionnalité dans la norme du langage C#, consultez l'article sur les spécifications.

Problème de champion : https://github.com/dotnet/csharplang/issues/2460

Conversion d’une expression conditionnelle

Pour une expression conditionnelle c ? e1 : e2, quand

  1. il n’existe aucun type commun pour e1 et e2, ou
  2. pour laquelle un type commun existe, mais l’une des expressions e1 ou e2 n’a pas de conversion implicite en ce type

nous définissons une nouvelle conversion d’expression conditionnelle implicite qui permet une conversion implicite de l’expression conditionnelle en n’importe quel type T pour lequel il existe une conversion à partir de l’expression de e1 en T et aussi de e2 en T. Si une expression conditionnelle n’a pas de type commun entre e1 et e2 et n’est pas soumise à une conversion d’expression conditionnelle, il s’agit d’une erreur.

Meilleure conversion à partir de l'expression

Nous changeons

Meilleure conversion à partir de l’expression

Étant donné une conversion implicite C1 qui convertit d’une expression E en un type T1, et une conversion implicite C2 qui convertit d’une expression E en un type T2, C1 est une meilleure conversion que C2 si E ne correspond pas exactement T2 et au moins l’une des conditions suivantes :

  • E correspond exactement à T1 (§12.6.4.5)
  • T1 est une meilleure cible de conversion que T2 (§12.6.4.7)

à

Meilleure conversion à partir de l’expression

Étant donné une conversion implicite C1 qui convertit d’une expression E en un type T1, et une conversion implicite C2 qui convertit d’une expression E en un type T2, C1 est une meilleure conversion que C2 si E ne correspond pas exactement T2 et au moins l’une des conditions suivantes :

  • E correspond exactement à T1 (§12.6.4.5)
  • C1 n’est pas une conversion d’expression conditionnelle et C2 est une conversion d’expression conditionnelle.
  • T1est une meilleure cible de conversion que T2 (§12.6.4.7) et soit C1 et C2 sont toutes deux des conversions d'expressions conditionnelles, soit aucune n'est une conversion d'expression conditionnelle.

Expression coulée

La spécification actuelle du langage C# indique

Une cast_expression de la forme (T)E, où T est un type et Eune unary_expression, effectue une conversion explicite (§10.3) de la valeur de E vers le type T.

En présence de la conversion d’expression conditionnelle, il peut y avoir plusieurs conversions possibles de E en T. Avec l’ajout de la conversion d'expression conditionnelle , nous préférons une autre conversion à une conversion d'expression conditionnelle , et utilisons la conversion d'expression conditionnelle uniquement en dernier recours.

Notes de conception

La raison du changement pour une meilleure conversion à partir d'une expression est de traiter un cas comme celui-ci :

M(b ? 1 : 2);

void M(short);
void M(long);

Cette approche présente deux petits inconvénients. Tout d’abord, ce n’est pas tout à fait la même chose que l’expression switch :

M(b ? 1 : 2); // calls M(long)
M(b switch { true => 1, false => 2 }); // calls M(short)

Il s’agit toujours d’un changement cassant, mais son étendue est moins susceptible d’affecter les programmes réels :

M(b ? 1 : 2, 1); // calls M(long, long) without this feature; ambiguous with this feature.

M(short, short);
M(long, long);

Il y a ambiguïté, car la conversion en long est meilleure pour le premier argument (parce qu’elle n’utilise pas la conversion d’expression conditionnelle), mais la conversion en short est meilleure pour le deuxième argument (parce que short est une meilleure cible de conversion que long). Ce changement de rupture semble moins préoccupant, car il ne modifie pas silencieusement le comportement d’un programme existant.

La raison des notes sur l'expression cast est de traiter un cas comme celui-ci :

_ = (short)(b ? 1 : 2);

Ce programme utilise actuellement la conversion explicite de int en short, et nous voulons conserver la signification actuelle du langage de ce programme. Le changement ne serait pas observable au moment de l’exécution, mais avec le programme suivant, il le serait :

_ = (A)(b ? c : d);

c est de type C, d est de type D, et il existe une conversion implicite définie par l’utilisateur de C en D, et une conversion implicite définie par l’utilisateur de D en A, et une conversion implicite définie par l’utilisateur de C en A. Si ce code est compilé avant C# 9.0, lorsque b est vrai, nous convertissons de c en D puis en A. Si nous utilisons la conversion d'expression conditionnelle , alors, lorsque b est vrai, nous convertissons directement de c à A, ce qui exécute une séquence différente de code utilisateur. Par conséquent, nous traitons la conversion d'expression conditionnelle en dernier recours dans un cast, afin de préserver le comportement existant.