42 votes

C# ?: Opérateur Conditionnel

J'ai cet extrait de C# 2.0 code source

object valueFromDatabase;
decimal result;
valueFromDatabase = DBNull.Value;

result = (decimal)(valueFromDatabase != DBNull.Value ? valueFromDatabase : 0);
result = (valueFromDatabase != DBNull.Value ? (decimal)valueFromDatabase : (decimal)0);

Le premier résultat de l'évaluation jette un invalide cast exception tandis que le second ne l'est pas. Quelle est la différence entre ces deux?

102voto

Eric Lippert Points 300275

Mise à JOUR: Cette question a été l'objet de mon blog le 27 Mai 2010. Merci pour la grande question!

Il y a un grand nombre de très déroutant réponses ici. Permettez-moi d'essayer de répondre précisément à votre question. Nous allons simplifier ce bas:

object value = whatever;
bool condition = something;
decimal result = (decimal)(condition ? value : 0);

Comment le compilateur interpréter la dernière ligne? Le problème rencontré par le compilateur, c'est que le type de l'expression conditionnelle doit être uniforme pour les deux branches; les règles de la langue ne vous permettent pas de revenir sur l'objet d'une branche et d'un int sur les autres. Les choix sont l'objet et l'int. Tous les int est convertible à l'objet, mais pas tous l'objet est convertibles en un int, donc le compilateur choisit objet. Donc c'est le même que

decimal result = (decimal)(condition ? (object)value : (object)0);

Par conséquent, le zéro retourné est un coffret int.

Ensuite, vous unbox l'int à la décimale. Il est illégal de unbox un coffret int nombre décimal. Pour les raisons, voir mon article de blog sur le sujet:

La représentation et de l'Identité

Fondamentalement, votre problème est que vous agissez comme si le casting de décimales ont été distribués, comme ceci:

decimal result = condition ? (decimal)value : (decimal)0;

Mais comme nous l'avons vu, ce n'est pas ce

decimal result = (decimal)(condition ? value : 0);

les moyens. Que signifie "faire à la fois des solutions de rechange dans les objets, et puis unbox l'objet".

12voto

Guffa Points 308133

La différence est que le compilateur ne peut pas déterminer un type de données qui est un bon match entre Object et Int32.

Vous pouvez convertir explicitement l' int valeur object pour obtenir le même type de données dans la deuxième et la troisième opérande de sorte qu'il compile, mais que de couse signifie que vous êtes boxing et unboxing de la valeur:

result = (decimal)(valueFromDatabase != DBNull.value ? valueFromDatabase : (object)0);

Qui va compiler, mais n'est pas exécuté. Vous devez cocher une valeur décimale à unbox comme une valeur décimale:

result = (decimal)(valueFromDatabase != DBNull.value ? valueFromDatabase : (object)0M);

5voto

Dzmitry Huba Points 3333

Le type de l'opérateur sera l'objet et dans le cas où le résultat doit être égal à 0, il sera implicitement en boîte. Mais 0 littérale est, par défaut, a le type int de sorte que vous boîte int. Mais avec un cast explicite virgule vous essayez de unbox ce qui n'est pas autorisée (boxed de type doit beaucoup à l'un de vous jeter en arrière pour). C'est pourquoi vous pouvez obtenir de l'exception.

Voici un extrait de Spécification C#:

La deuxième et la troisième des opérandes de l' ?: l'opérateur de contrôler le type de l'expression conditionnelle. Soit X et Y des types de la deuxième et de la troisième opérande. Ensuite,

  • Si X et Y sont du même type, puis c'est le type de l'expression conditionnelle.
  • Sinon, si une conversion implicite (§6.1) existe à partir de X à Y, mais pas à partir de Y à X, alors Y est le type de la expression conditionnelle.
  • Sinon, si une conversion implicite (§6.1) existe à partir de Y à X, mais pas de X à Y, alors X est le type de la expression conditionnelle.
  • Sinon, pas de type d'expression peut être déterminé, et une erreur de compilation se produit.

4voto

Philippe Leybaert Points 62715

Votre ligne doit être:

result = valueFromDatabase != DBNull.value ? (decimal)valueFromDatabase : 0m;

0m est la constante décimale zéro

Les deux parties d'un opérateur conditionnel doit correspondre au même type de données

3voto

ongle Points 4567

Le x : y part besoin d'un type commun, la base de données de la valeur est probablement une sorte de flotteur et 0 est un entier (int). Ce qui se passe avant la fonte à la décimale. Essayez ": 0.0" ou ": 0D".

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