11

J'essaie d'utiliser l'opérateur conditionnel, mais je suis accroché sur le type qu'il pense que le résultat devrait être.Résultat du type avec l'opérateur conditionnel en C#

est un exemple ci-dessous que j'ai trouvé le moyen de montrer la question que j'ai:

class Program 
{ 
    public static void OutputDateTime(DateTime? datetime) 
    { 
     Console.WriteLine(datetime); 
    } 

    public static bool IsDateTimeHappy(DateTime datetime) 
    { 
     if (DateTime.Compare(datetime, DateTime.Parse("1/1")) == 0) 
      return true; 

     return false; 
    } 

    static void Main(string[] args) 
    { 
     DateTime myDateTime = DateTime.Now; 
     OutputDateTime(IsDateTimeHappy(myDateTime) ? null : myDateTime); 
     Console.ReadLine();      ^
    }            | 
}             | 
// This line has the compile issue ---------------+ 

Sur la ligne indiquée ci-dessus, je reçois l'erreur de compilation suivante:

Type d'expression conditionnelle ne peut pas être déterminé car il n'y a pas de conversion implicite entre '< null>' et 'System.DateTime'

Je suis confus parce que le paramètre est un type Nullable (DateTime?). Pourquoi a-t-il besoin de convertir du tout? Si c'est null, utilisez-le, s'il s'agit d'une date, utilisez-le.

j'avais l'impression que:

condition ? first_expression : second_expression; 

était le même que:

if (condition) 
    first_expression; 
else 
    second_expression; 

Il est clair que ce n'est pas le cas. Quel est le raisonnement derrière cela?

(REMARQUE:.?. Je sais que si je fais « MyDateTime » DateTime nullable il fonctionnera Mais pourquoi est-il besoin

Comme je l'ai dit plus tôt c'est un exemple artificiel Dans mon exemple réel " myDateTime "est une valeur mappée de données qui ne peut pas être rendue nulle.)

+0

double possible de [affectation de l'opérateur conditionnel avec des types Nullable ?] (Http://stackoverflow.com/questions/75746/conditional-operator-assignment-with-nullablevalue-types) – nawfal

+0

en double possible de [types nullables et la opérateur ternaire: pourquoi est \ '? 10: null \ 'interdit?] (Http://stackoverflow.com/questions/858080/nullable-types-and-the-ternary-operator-why-is-10-null-forbidden) –

Répondre

22

Le compilateur ne déduit pas le type du résultat de l'opérateur conditionnel de l'utilisation du résultat, mais des types de ses arguments. Le compilateur échoue lorsqu'il voit cette expression, car il ne peut pas déduire le type du résultat:

IsDateTimeHappy(myDateTime) ? null : myDateTime; 

Depuis null et DateTime ne sont pas compatibles, vous devez dire au compilateur ce type doit être. Une distribution devrait faire l'affaire:

DateTime? x = IsDateTimeHappy(myDateTime) ? (DateTime?)null : myDateTime; 
OutputDateTime(x); 

Maintenant, le compilateur n'aura aucun problème.Vous pouvez également écrire ci-dessus sur une ligne si vous préférez (mais je ne serais probablement pas le faire):

OutputDateTime(IsDateTimeHappy(myDateTime) ? (DateTime?)null : myDateTime); 

Eric Lippert a une good answer qui est aussi pertinente ici et va dans plus de détails sur la façon dont le compilateur détermine les types .

+0

Aussi une solution moins verbeuse de déclaration myDateTime comme 'DateTime?' pour commencer: 'DateTime? myDateTime = DateTime.Now; ' –

1

La conversion implicite n'est pas autorisée par l'instruction return. Si vous aviez

if (condition) 
    return first_expression; 
else 
    return second_expression; 

Ensuite, vous compareriez les pommes aux pommes. Et vous n'auriez aucun problème - comme vous l'avez dit.

Dans votre cas, vous disposez de beaucoup d'espace sur la pile pour un DateTime - qui est un type de valeur non nullable. Donc vous faites une déclaration qui n'a aucun sens pour le compilateur. Si vous dites, je vais vous passer un A ou un B, puis le A et le B doivent être la même chose. Dans votre cas, le B ne peut jamais être un A.

2

La raison en est que l'opérateur ternaire s'attend à ce que les deux opérandes soient du même type. L'opérateur entier est travaillé AVANT qu'il ne soit assigné à un résultat (dans ce cas passé dans une fonction), ainsi le compilateur ne peut pas savoir quel est le type de résultat.

IsDateTimeHappy(myDateTime) ? null : myDateTime 

Dans le cas ci-dessus il n'y a pas de chemin de conversion entre null et DateTime. Dès que vous lancez un d'eux DateTime?, le compilateur peut convertir l'autre:

IsDateTimeHappy(myDateTime) ? (DateTime?)null : myDateTime 
//OR 
IsDateTimeHappy(myDateTime) ? null : (DateTime?)myDateTime 

La ligne de poing code ci-dessus fonctionne parce que le compilateur peut convertir DateTime-DateTime? par un opérateur de conversion implicite:

//In Nullable<T> 
public static implicit operator T?(T value); 

La deuxième ligne fonctionne parce que null peut être affectée à DateTime? puisque ce dernier est un type de référence.

0

Ce que le compilateur dit est:

If IsDateTimeHappy(myDateTime) is false , then I need to return a value of type DateTime equal to myDateTime . If it is true , then I need to return a value equal to null , but you haven't told me what type it should be!

Voilà pourquoi la réponse de Mark est la solution. Après avoir fourni une distribution indiquant au compilateur quel type de valeur sera renvoyé si la condition est true, elle peut vérifier si les valeurs de retour true et false peuvent être converties en (ou sont) du même type.

Cheers Mark! ;-)

0

Au lieu de null, utilisez default(DateTime?), puis les deux côtés de la ternaire auront des types compatibles.