61 votes

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

Je suis un peu perplexe face à cette petite bizarrerie du C# :

Variables données :

Boolean aBoolValue;
Byte aByteValue;

Ce qui suit se compile :

if (aBoolValue) 
    aByteValue = 1; 
else 
    aByteValue = 0;

Mais ce ne sera pas le cas :

aByteValue = aBoolValue ? 1 : 0;

L'erreur dit : "Impossible de convertir implicitement le type 'int' en 'byte'."

Et bien sûr, cette monstruosité va se compiler :

aByteValue = aBoolValue ? (byte)1 : (byte)0;

Qu'est-ce qui se passe ici ?

EDITAR:

Utilisation de VS2008, C# 3.5

69voto

Eric Lippert Points 300275

Il s'agit d'une question assez fréquemment posée.

En C#, nous raisonnons presque toujours de l'intérieur vers l'extérieur. Lorsque vous voyez

x = y;

nous déterminons quel est le type de x, quel est le type de y, et si le type de y est compatible avec x. Mais nous n'utilisons pas le fait que nous connaissons le type de x lorsque nous calculons le type de y.

C'est parce qu'il peut y avoir plus d'un x :

void M(int x) { }
void M(string x) { }
...
M(y); // y is assigned to either int x or string x depending on the type of y

Nous besoin de être capable de déterminer le type d'une expression sans en sachant à quoi elle est affectée. Type de flux d'informations out d'une expression, et non en une expression.

Pour déterminer le type de l'expression conditionnelle, nous déterminons le type de la conséquence et des expressions alternatives, nous choisissons le type le plus général des deux, et cela devient le type de l'expression conditionnelle. Ainsi, dans votre exemple, le type de l'expression conditionnelle est "int", et ce n'est pas une constante (sauf si l'expression conditionnelle est constante true ou constante false). Puisque ce n'est pas une constante, vous ne pouvez pas l'assigner à byte ; le compilateur raisonne uniquement à partir des types, et non à partir des valeurs, lorsque le résultat n'est pas une constante.

L'exception à toutes ces règles est constituée par les expressions lambda, où les informations de type fait du contexte dans le lambda. Obtenir une logique correcte a été très difficile.

12voto

John Knoeller Points 20754

J'utilise VS 2005, pour et je peux reproduire, pour bool & Boolean, mais pas pour true

 bool abool = true;
 Boolean aboolean = true;
 Byte by1 = (abool ? 1 : 2);    //Cannot implicitly convert type 'int' to 'byte'
 Byte by2 = (aboolean ? 1 : 2); //Cannot implicitly convert type 'int' to 'byte'
 Byte by3 = (true ? 1 : 2);     //Warning: unreachable code ;)

La solution de contournement la plus simple semble être ce casting

 Byte by1 = (Byte)(aboolean ? 1 : 2);

Donc, oui, il semble que l'opérateur ternaire fasse en sorte que les constantes "fixent" leurs types en tant qu'ints et désactivent la conversion implicite de type que vous obtiendriez autrement des constantes qui s'adaptent au plus petit type.

7voto

Hamish Grubijan Points 2078

Je n'ai peut-être pas une grande réponse pour vous, mais si vous faites cela dans de nombreux endroits, vous pourriez déclarer :

private static readonly Byte valueZero = (byte)0;
private static readonly Byte valueOne = (byte)1;

et juste ces variables. Vous pouvez vous en sortir en utilisant const si elle est locale au projet.

EDITAR: en utilisant readonly n'aurait pas de sens - ils ne sont jamais censés changer.

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