Pourquoi l'opérateur is renvoie-t-il false lorsqu'il est donné null?


135

Il me semble que l' isopérateur est un peu incohérent.

bool Test()
{
    // Returns false, but should return true.
    return null is string;
}

On s'attend à ce que la nullvaleur appartienne à n'importe quel type référence (ou nullable). Et en effet, la spécification du langage C # dit quelque chose qui prend en charge cette hypothèse, par exemple (6.1.6 Conversions de référence implicites):

Les conversions de référence implicites sont les suivantes:
...
• Du littéral nul vers n'importe quel type de référence.

La description (7.10.10 L'opérateur is) de l' isopérateur commence par dire que l'expression (E is T)aboutira à vrai lorsqu'une conversion de référence de Eà Texiste, mais ensuite les auteurs continuent en excluant explicitement le cas où Eest le nulllittéral ou a une nullvaleur .

Pourquoi font-ils ça? Cela me semble contre-intuitif.


Pourquoi ils ont explicitement exclu null est au mieux une question pour programmers.stackoverflow.com
Variable misérable

2
Je ne peux pas annuler mon vote serré, mais ces questions sont bien ici: meta.stackexchange.com/questions/36850/…
Merlyn Morgan-Graham

en java null typeof Objectrenvoie également false
ratchet freak

On suppose que null is stringsont true, et cela impliquait que nullest string. Supposons également que null is Nullable<int>c'est true, ce qui implique que nullc'est un Nullable<int>. Maintenant, répondez à cette question: de quel type s'agit-il null?
un CVn

1
@Michael Kjörling: Non sequitur. D'après les faits mentionnés (null est une chaîne, null est un Nullable <int>), il ne s'ensuit pas que je devrais être en mesure de répondre à cette question.
Gebb

Réponses:


195

Cette question a fait l' objet de mon blog le 30 mai 2013 . Merci pour la bonne question!


Vous regardez une allée vide.

Quelqu'un vous demande "votre entrée peut-elle contenir une Honda Civic?"

Oui. Oui il peut.

Quelqu'un vous indique une deuxième allée. Il est également vide. Ils demandent "Le contenu actuel de mon entrée peut-il tenir dans votre entrée?"

Oui évidemment. Les deux allées sont vides! Il est donc clair que le contenu de l'un peut s'intégrer dans l'autre, car il n'y a pas de contenu de l'un ou l'autre en premier lieu.

Quelqu'un vous demande "Votre entrée contient-elle une Honda Civic?"

Non.

Vous pensez que l' isopérateur répond à la deuxième question: étant donné cette valeur, s'inscrit-elle dans une variable de ce type? Une référence nulle tient-elle dans une variable de ce type? Oui.

Ce n'est pas la question à laquelle isrépond l' opérateur. La question à laquelle l' isopérateur répond est la troisième question. y is Xne demande pas " est yune valeur légale d'une variable de type X? " Il demande " Une yréférence valide à un objet de type X? " Puisqu'une référence nulle n'est pas une référence valide à un objet de tout type, la réponse est "non ". Cette allée est vide; il ne contient pas de Honda Civic.

Une autre façon de voir les choses est que cela y is Xrépond à la question "si je disais y as X, est-ce que j'obtiendrai un résultat non nul? Si y est nul, la réponse est clairement non!


Pour approfondir votre question:

On s'attend à ce que la valeur nulle appartienne à n'importe quel type référence (ou nullable)

On supposerait implicitement qu'un type est un ensemble de valeurs , et que la compatibilité d'affectation d'une valeur y avec une variable de type X n'est ni plus ni moins que de vérifier si y est membre de l'ensemble x .

Bien que ce soit une façon extrêmement courante de regarder les types, ce n'est pas la seule façon de regarder les types, et ce n'est pas la façon dont C # regarde les types. Les références nulles sont des membres sans type en C #; la compatibilité d'affectation est pas simplement vérifier un ensemble pour voir si elle contient une valeur. Juste parce qu'une référence nulle est compatible avec l'affectation n'est pas avec une variable de type référence X que null est un membre de type X. La relation "est affectation compatible avec" et la relation "est membre de type" ont évidemment beaucoup de se chevauchent, mais ils ne sont pas identiques dans le CLR.

Si les réflexions sur la théorie des types vous intéressent, consultez mes articles récents sur le sujet:

Quelle est cette chose que vous appelez un «type»? Partie un

Quelle est cette chose que vous appelez un «type»? Deuxième partie


@Gebb: Heureux de vous aider. Cet article pourrait également vous intéresser: blogs.msdn.com/b/ericlippert/archive/2010/09/16/…
Eric Lippert


y is Xne demande pas "est yune valeur légale d'une variable de type X?" Il demande "Une yréférence valide à un objet est-elle de type X?" C'était le but! Merci!
Jalal

Mais si je demande y is int?, alors je demanderais "Votre entrée contient-elle une Honda Civic ou rien?". Pourquoi la réponse est-elle toujours non lorsque votre allée est vide? Si vous regardez sous le capot, cela ne fait qu'empirer, car la question devient "Votre entrée contient-elle une Honda Civic ou un panneau indiquant" Pas de Honda Civic ici "?". Même si votre allée contient ledit panneau, la réponse est toujours non.
Fax le

1
@Gerard: Quand je donne des réponses longues, verbeuses et bavardes, les gens me disent qu'elles devraient être plus courtes, et quand je donne des réponses concises et laconiques, les gens me disent qu'elles devraient être plus longues. Ma conclusion est la suivante: les gens aiment se plaindre. Puisque vous avez des sentiments sur ce qui constitue une bonne réponse à cette question vieille de huit ans, je vous suggère de nous montrer ce qui fait une bonne réponse en y répondant vous-même, afin que nous puissions apprendre.
Eric Lippert

24

Je pense que null is stringretourner faux est très intuitif. Null ne signifie rien et ce n'est certainement pas une chaîne. Il devrait donc renvoyer false. Bien que ce soit un choix que les concepteurs de langage ont fait, il est très intuitif lorsque vous considérez la signification réelle de null.


2
+1 parce que la question est vraiment de savoir si c'est intuitif et ne remet pas en question les spécifications, dont l'OP est déjà conscient. Si vous le demandez en anglais "est nullune chaîne", la réponse est non, ce n'est pas le cas, ce qui est différent de "est nullassignable à string"
Davy8

null is stringest assez intuitif, (string)null is stringpeut nécessiter une pause si vous n'êtes pas vraiment familier avec le fonctionnement d'une référence nulle en C #.
decPL

24

Le nulllittéral peut être affecté à n'importe quel type de référence. Ce n'est pas un type en soi. C'est un littéral spécial qui représente une référence nulle.

Dans le cas où iscela reviendrait truequand un nullserait passé, que seriez-vous capable de faire avec le nulllittéral? Rien - ça l'est null. Quel serait l'intérêt de le faire revenir, truesauf pour des questions confuses?


Peu importe - en termes d'intuitivité, lisez le code en anglais et dites-moi:

null is string;

Quand je vois cela, cela semble poser la question is "nothing" a string?. Mon intuition me dit que non, ce n'est pas - c'est nothing.


Ce n'est pas grave, mais c'est aussi une chaîne, non? Mais pourquoi le (null is string)retour flase-t-il alors?
Gebb

Je l'aurais formulé dans l'autre sens. Tout type de référence peut être nul. null est juste nul.
Mark H

@Oded, est-ce que la valeur nulle est une valeur valide, par exemple, du type d'objet? Je peux l'assigner à une variable de ce type, non? Donc la réponse semble être oui, la valeur est parfaitement valide, et je suppose que l' (null is object)expression devrait vérifier exactement cela.
Gebb

@Gebb: N'oubliez pas que les ValueTypes sont également des objets, mais pas des types de référence.
Mark H

1
@Oded: "Quel serait l'intérêt de rendre vrai si ce n'est pour des choses confuses?" En fait, cela rendrait le langage plus logique. Considérez ces deux points: (1) l' isopérateur vérifie si une conversion de référence (nous n'avons pas besoin d'autres types de conversion ici) existe; (2) nullpeut être converti en n'importe quel type de référence. Par conséquent (null is T), où T est un type de référence doit retourner true. Mais non, nous avons ici cette exception explicite, ce qui me semble déroutant.
Gebb

12

http://msdn.microsoft.com/en-us/library/scekt9xw%28v=vs.71%29.aspx

Une expression is prend la valeur true si les deux conditions suivantes sont remplies:

  • expression n'est pas nulle.
  • l'expression peut être convertie en type. Autrement dit, une expression de conversion de la forme (type (expression) se terminera sans lever d'exception. Pour plus d'informations, voir 7.6.6 Expressions de conversion.

1
Quoi qu'il en soit, la documentation indique seulement que l'expression ne peut pas être nulle (que nous savons déjà), mais elle ne dit pas pourquoi
nom d'utilisateur

Pourquoi le voudriez-vous autrement?
Variable misérable

1
@username: Cette réponse explique son fonctionnement mécanique et cite une référence, qui vous donne un modèle avec lequel travailler. Vous demandez la signification de l'univers ici. Je suppose que vous avez de la chance que notre dieu fréquente SO;)
Merlyn Morgan-Graham

10

En pratique, avoir "null est T == false" m'évite de taper du code supplémentaire:

Au lieu d'avoir à dire

if (X != null && X is Foo) {}

Je peux juste dire

if (X is Foo) {}

et en finir.


8

la nullvaleur

Je l'ai cité à partir de votre question parce que cela semble aller au cœur du problème. null n'est pas une valeur - c'est l'absence de valeur. Le but de isme semble être de répondre à la question:

Si je lance Evers T, vais-je réussir à obtenir un T?

Maintenant, alors que vous pouvez jeter nullà T sans erreur , après avoir fait de sorte que vous ne « avez T» - vous avez encore rien obtenu. Donc ce n'est pas le cas où null"est" a T, donc isrenvoie false.


3

En Java il y a un opérateur qui fait exactement la même chose, mais il a beaucoup plus le nom: instanceof. C'est très intuitif là-bas qui null instanceof Stringrenvoie false, car null n'est une instance de rien, encore moins de a String. Donc, lors de l'utilisationnull la version de Java, c'est un peu plus intuitif.

Cependant, ces deux opérateurs renvoient true lorsqu'on leur demande de parcourir également toute la hiérarchie. Par exemple. si l'instance de Stringest un Object. Et ici, c'est Java qui est un peu moins intuitif (car une instance a en fait un type très spécifique) et C # isest plus intuitif (car tout String est unObject profond à l'intérieur).

Bottom line: si vous essayez de décrire une logique assez avancée en un mot, vous risquez d'avoir peu de gens confus, d'une manière ou d'une autre. Il semble que la plupart des gens étaient d'accord sur un sens et ceux qui n'étaient pas d'accord, ont dû s'adapter.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.