En C #, pourquoi un opérateur conditionnel ne peut-il pas implémenter implicitement un type nullable?

Je suis curieux de savoir pourquoi une dissortingbution implicite échoue dans …

int? someValue = SomeCondition ? ResultOfSomeCalc() : null; 

et pourquoi je dois effectuer une dissortingbution explicite à la place

 int? someValue = SomeCondition ? ResultofSomeCalc() : (int?)null; 

Il me semble que le compilateur dispose de toutes les informations nécessaires pour prendre une décision de casting implicite, non?

La section pertinente de la spécification C # 3.0 est 7.13, l’opérateur conditionnel:

Les deuxième et troisième opérandes de l’opérateur?: Contrôlent le type de l’expression conditionnelle. Soit X et Y les types des deuxième et troisième opérandes. Ensuite,

Si X et Y sont du même type, il s’agit du type du conditionnel. Sinon, si une conversion implicite (§6.1) existe de X à Y, mais pas de Y à X, alors Y est le type de l’expression conditionnelle. Sinon, si une conversion implicite (§6.1) existe de Y à X, mais pas de X à Y, 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.

Je suis également contrarié par le fait qu’il ne peut pas déduire le type en fonction de l’affectation, surtout lorsqu’il s’agit d’un type de valeur. Il y a des raisons cependant quand vous entrez dans les hiérarchies d’objects.

Si “ResultOfSomeCalc ()” renvoyait un “int?”, Cela fonctionnerait . C # doit déterminer le type indépendamment de ce qui se trouve à gauche de la tâche. Donc, vous lui dites que vous retournerez un null ou un int – et la logique du compilateur n’existe pas pour lui substituer un Nullable en tant que dénominateur commun.

Notez que ces variantes fonctionnent, et cela peut vous aider à comprendre:

 object someValue = true ? new Nullable(ResultOfSomeCalc()) : null; object someValue = true ? (int?)ResultOfSomeCalc() : null; 

J’espère que cela t’aides.

Il semble bien que le compilateur devrait pouvoir résoudre ce problème, mais il existe un autre moyen de le faire, en utilisant le mot-clé default. C’est peut-être le plus petit morceau moins laid que le casting:

 int? someValue = SomeCondition ? ResultofSomeCalc() : default(int?); 

Cette utilisation de défaut ne semble pas être bien documentée, mais ça fonctionne. Au moins, cela vous évite d’avoir à coder des valeurs magiques dans votre code (j’affirme que null / zéro / faux / etc. sont effectivement des valeurs magiques).

Voir aussi Pourquoi ce code est-il invalide en C #?

Si votre fonction ResultofSomeCalc () renvoie int? alors cela fonctionnera.

Si votre fonction renvoie int, le compilateur émet l’avertissement suivant: Le type d’expression conditionnelle ne peut pas être déterminé car il n’y a pas de conversion implicite entre ‘int’ et ”.
Je suppose que c’est ce que vous voyez. Les deux expressions de l’opérateur conditionnel “?:” Doivent avoir le même type ou doivent être convertibles en un même type via une conversion implicite.

Changez le type de résultat de ResultOfSomeCalc en int ?, ou vous aurez besoin de la conversion sur l’expression null.

Définissez le type de retour de votre fonction ResultOfSomeCalc () comme nullabel int like (int?)
int? someValue = (int?) SomeCondition? ResultofSomeCalc (): (int?) Null;