web-dev-qa-db-fra.com

Pourquoi la correspondance de modèle sur une valeur NULL entraîne-t-elle des erreurs de syntaxe?

J'aime utiliser pattern-matching sur un nullable int i.e. int?:

int t  = 42;
object tobj = t;    
if (tobj is int? i)
{
    System.Console.WriteLine($"It is a nullable int of value {i}");
}

Cependant, cela entraîne les erreurs de syntaxe suivantes:

«i)» est marqué d'une ligne ondulée rouge.

L'expression est compilée lors de l'utilisation de l'ancien opérateur is:

int t = 42;
object tobj = t;    
if (tobj is int?)
{
    System.Console.WriteLine($"It is a nullable int");
}


string t = "fourty two";
object tobj = t;
if (tobj is string s)
{
    System.Console.WriteLine($@"It is a string of value ""{s}"".");
}

Fonctionne également comme prévu.

(J'utilise c # -7.2 et testé avec les deux .net-4.7.1 et .net-4.6.1 )

Je pensais qu'il y avait quelque chose à faire avec la préséance de l'opérateur. Par conséquent, j'ai essayé d'utiliser des parenthèses à plusieurs endroits mais cela n'a pas aidé.

Pourquoi donne-t-il ces erreurs de syntaxe et comment puis-je les éviter?

10
Kasper van den Berg

Le modèle de type sous ses différentes formes: x is T y, case T y etc, ne correspond toujours pas lorsque x est null . Cela est dû au fait que null n'a pas le type , et demande donc "cette null est-elle de ce type?" est une question dénuée de sens.

Par conséquent, t is int? i ou t is Nullable<int> i n'a pas de sens en tant que modèle: Soit t est un int, auquel cas t is int i correspondra de toute façon, ou bien il s'agira de null, auquel cas aucun modèle ne pourra correspondre.

Et c’est la raison pour laquelle t is int? i ou t is Nullable<int> i ne sont pas, et ne le seront probablement jamais, pris en charge par le compilateur.

La raison pour laquelle vous obtenez des erreurs supplémentaires du compilateur lorsque vous utilisez t is int? i est due au fait que, par exemple, t is int? "it's an int" : "no int here" est une syntaxe valide. Par conséquent, le compilateur ne comprend pas vos tentatives d'utilisation de ? pour un type nullable dans ce contexte.

Pour ce qui est de savoir comment les éviter, la réponse évidente (bien que probablement pas très utile) est la suivante: n’utilisez pas de types nullable comme modèles de type. Une réponse plus utile vous obligerait à expliquer pourquoi vous essayez de le faire.

13
David Arno

Changez votre code en:

int t = 42;
object tobj = t;
if (tobj is Nullable<int> i)
{
    Console.WriteLine($"It is a nullable int of value {i}");
}

Cela produit le plus utile:

  • CS8116: Il n'est pas légal d'utiliser le type nullable 'int?' dans un motif; utilisez le type sous-jacent 'int' à la place  (Impossible de trouver la documentation sur CS8116 à référencer)

D'autres utilisateurs (utilisateur @ Blue0500 sur github ) ont balisé ce comportement en tant que bogue numéro Roslyn # 20156 . Réagissant au numéro Roslyn # 20156 , Julien Couvreur de Microsoft a déclaré qu'il pensait que c'était à dessein.
Neal Gafter de Microsoft travaillant sur Roslyn a également déclaré/ de meilleurs diagnostics sont nécessaires pour utiliser le type Nullable: switch pattern .

Donc, le message d'erreur peut être évité en utilisant:

int t = 42;
object tobj = t;
if (tobj == null)
{
    Console.WriteLine($"It is null");
}
else if (tobj is int i)
{
    Console.WriteLine($"It is a int of value {i}");
}

Sauf pour les problèmes lors de l'analysetobj is int? i, la question de savoir pourquoi tobj is int? i ou tobj is Nullable<int> i n'est toujours pas laissée posée.

2
Kasper van den Berg