¿Por qué el operador is devuelve falso cuando se le da un valor nulo?


135

Me parece que el isoperador es un poco inconsistente.

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

Uno espera que el nullvalor pertenezca a cualquier tipo de referencia (o anulable). Y, de hecho, la especificación del lenguaje C # dice algo que respalda esta hipótesis, por ejemplo (6.1.6 Conversiones de referencia implícitas):

Las conversiones de referencia implícitas son:
...
• Desde el literal nulo a cualquier tipo de referencia.

La descripción (7.10.10 El operador is) del isoperador comienza diciendo que la expresión (E is T)dará como resultado verdadero cuando existe una conversión de referencia de Ea T, pero luego los autores continúan excluyendo explícitamente el caso cuando Ees nullliteral o tiene un nullvalor .

¿Por qué hacen eso? A mí me parece contradictorio.


Por qué excluyeron explícitamente nulo es, en el mejor de los casos, una pregunta para programmers.stackoverflow.com
Variable miserable del

2
No puedo rescindir mi voto cerrado, pero estas preguntas están bien aquí: meta.stackexchange.com/questions/36850/…
Merlyn Morgan-Graham

en Java null typeof Objecttambién devuelve false
trinquete monstruo

Suponga que null is stringfueron true, y esto implica que nulles un string. También suponga que null is Nullable<int>es true, lo que implica que nulles un Nullable<int>. Ahora, responda esta pregunta: ¿de qué tipo es null?
un CVn

1
@Michael Kjörling: Non sequitur. De los hechos mencionados (nulo es una cadena, nulo es Nullable <int>) no se deduce que deba poder responder esa pregunta.
Gebb

Respuestas:


195

Esta pregunta fue el tema de mi blog el 30 de mayo de 2013 . Gracias por la gran pregunta!


Estás mirando una entrada vacía.

Alguien le pregunta "¿puede su camino de entrada sostener un Honda Civic?"

Si. Sí puede.

Alguien te señala un segundo camino de entrada. También está vacío. Preguntan "¿Puede el contenido actual de mi entrada encajar en su entrada?"

Si obviamente. ¡Ambas entradas están vacías! Entonces, claramente, el contenido de uno puede caber en el otro, porque no hay contenido de ninguno de ellos en primer lugar.

Alguien le pregunta "¿Su entrada contiene un Honda Civic?"

No, no lo hace.

Estás pensando que el isoperador responde la segunda pregunta: dado este valor, ¿cabe en una variable de ese tipo? ¿Una referencia nula cabe en una variable de este tipo? Si lo hace

Esa no es la pregunta que responde el isoperador. La pregunta que responde el isoperador es la tercera pregunta. y is Xno pregunta "¿ es yun valor legal de una variable de tipo X? " Pregunta " ¿Es yuna referencia válida a un objeto de tipo X? " Dado que una referencia nula no es una referencia válida a ningún objeto de ningún tipo, la respuesta es "no ". Esa entrada está vacía; No contiene un Honda Civic.

Otra forma de verlo es que y is Xresponde la pregunta "si dijera y as X, ¿obtendría un resultado no nulo? Si y es nulo, ¡claramente la respuesta es no!


Para profundizar un poco en su pregunta:

Uno espera que el valor nulo pertenezca a cualquier tipo de referencia (o anulable)

Uno supondría implícitamente que un tipo es un conjunto de valores , y que la compatibilidad de asignación de un valor y con una variable de tipo X no es más ni menos que verificar si y es miembro del conjunto x .

Aunque esa es una forma extremadamente común de ver los tipos, no es la única forma de ver los tipos, y no es la forma en que C # mira los tipos. Las referencias nulas son miembros de ningún tipo en C #; la compatibilidad de asignaciones no es simplemente verificar un conjunto para ver si contiene un valor. El hecho de que una referencia nula sea una asignación compatible con una variable de tipo de referencia X no significa que nulo sea miembro del tipo X. La relación "es una asignación compatible con" y la relación "es un miembro del tipo" obviamente tiene muchas se superponen, pero no son idénticos en el CLR.

Si le interesan las reflexiones sobre la teoría de tipos, consulte mis artículos recientes sobre el tema:

¿Qué es esta cosa que llamas un "tipo"? Parte uno

¿Qué es esta cosa que llamas un "tipo"? La segunda parte


@Gebb: Me alegro de ayudar. Este artículo también puede ser de su interés: blogs.msdn.com/b/ericlippert/archive/2010/09/16/…
Eric Lippert

Eric convirtió esto en una publicación de blog: ericlippert.com/2013/05/30/what-the-meaning-of-is-is
Kevin Cathcart

y is Xno pregunta "¿es yun valor legal de una variable de tipo X?" Pregunta "¿Es yuna referencia válida a un objeto de tipo X?" Ese fue todo el punto! ¡Gracias!
Jalal

Pero si pregunto y is int?, entonces estaría preguntando "¿Su entrada contiene un Honda Civic o nada?". ¿Por qué la respuesta sigue siendo negativa cuando la entrada está vacía? Si observa debajo del capó, la situación empeora, ya que la pregunta es "¿Contiene su Honda Civic o un letrero que dice 'No Honda Civic here'?". Incluso si su camino de entrada contiene dicho signo, la respuesta sigue siendo no.
Fax

1
@Gerard: Cuando doy respuestas largas, verbosas y habladoras, la gente me dice que deberían ser más cortas, y cuando doy respuestas concisas y lacónicas, la gente me dice que deberían ser más largas. Mi conclusión es: a la gente le gusta quejarse. Dado que tiene sentimientos sobre lo que hace una buena respuesta a esta pregunta de ocho años, mi sugerencia es que nos muestre lo que hace una buena respuesta al responderla usted mismo, para que podamos aprender.
Eric Lippert

24

Creo que null is stringdevolver falso es muy intuitivo. Nulo no significa nada, y definitivamente no es una cadena. Por lo tanto, debe devolver falso. Si bien es una elección que hicieron los diseñadores de idiomas, es muy intuitiva cuando se considera el significado del mundo real de nulo.


2
+1 porque la pregunta es realmente si es intuitiva y no cuestiona la especificación, que el OP ya conoce. Si lo preguntas como una oración en inglés "es nulluna cadena" la respuesta es no, no lo es, lo cual es diferente de "es nullasignable a string"
Davy8

null is stringes bastante intuitivo, (string)null is stringpuede requerir una pausa si no está realmente familiarizado con el funcionamiento de una referencia nula en C #.
decPL

24

El nullliteral se puede asignar a cualquier tipo de referencia. Es no un tipo en una de sí mismo. Es un literal especial que representa una referencia nula.

En el caso de que isvolvería truecuando nullse pasara un, ¿qué podría hacer con el nullliteral? Nada, lo es null. ¿Cuál sería el punto de regresar si no fuera truepor cuestiones confusas?


Independientemente, en términos de cuán intuitivo es, lea el código en inglés y dígame:

null is string;

Cuando veo eso, parece estar haciendo la pregunta is "nothing" a string?. Mi intuición me dice que no, no lo es, lo es nothing.


Eso está bien, pero también es una cuerda, ¿verdad? Pero (null is string)entonces, ¿ por qué vuelve flase?
Gebb

Lo habría expresado al revés. Cualquier tipo de referencia puede ser nulo. nulo es simplemente nulo.
Mark H

@Oded ¿Entonces el valor nulo es un valor válido de, digamos, el tipo de objeto? Puedo asignarlo a una variable de este tipo, ¿verdad? Entonces, la respuesta parece ser sí, el valor es perfectamente válido, y supongo que la (null is object)expresión debería verificar exactamente eso.
Gebb

@Gebb: No olvide que los ValueTypes también son objetos, pero no tipos de referencia.
Mark H

1
@Oded: "¿Cuál sería el punto de que vuelva a ser cierto, excepto por cuestiones confusas?" En realidad, haría el lenguaje más lógico. Considere estos dos puntos: (1) el isoperador verifica si existe una conversión de referencia (no necesitamos otros tipos de conversión aquí); (2) nullse puede convertir a cualquier tipo de referencia. Por lo tanto (null is T), donde T es un tipo de referencia debe devolver verdadero. Pero no, aquí tenemos esa excepción explícita, que es lo que me parece confuso.
Gebb

12

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

Una expresión is se evalúa como verdadera si se cumplen las dos condiciones siguientes:

  • La expresión no es nula.
  • La expresión se puede convertir al tipo. Es decir, una expresión de conversión del formulario (tipo (expresión) se completará sin generar una excepción. Para obtener más información, consulte 7.6.6 Expresiones de conversión.

1
De todos modos, la documentación solo indica que la expresión no puede ser nula (que ya sabemos), pero no dice por qué
nombre de usuario

¿Por qué lo querrías de otra manera?
Variable miserable el

1
@username: esta respuesta explica la forma en que funciona mecánicamente y cita una referencia, que le brinda un modelo para trabajar. Estás preguntando el significado del universo aquí. Supongo que tienes suerte de que nuestro dios frecuenta SO;)
Merlyn Morgan-Graham

10

Como cuestión práctica, tener "nulo es T == falso" me ahorra escribir código adicional:

En lugar de tener que decir

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

Solo puedo decir

if (X is Foo) {}

y terminemos con eso.


8

el nullvalor

He citado esto de su pregunta porque parece llegar al meollo del asunto. null no es un valor, es la ausencia de un valor. El propósito de ismí parece ser responder la pregunta:

Si lanzo Ea T, ¿obtendré un éxito T?

Ahora, mientras se puede echar nulla T sin error , después de hacer lo que no "tiene un T" - nada todavía tienes. Por lo tanto, no es el caso de que null"es" a T, por lo que isdevuelve falso.


3

En Java hay un operador que hace exactamente lo mismo, pero tiene nombre mucho más tiempo: instanceof. Es muy intuitivo que null instanceof Stringdevuelve falso, porque nulo no es una instancia de nada, mucho menos a String. Entonces, cuando se usanull la versión de Java es un poco más intuitivo.

Sin embargo, ambos operadores devuelven verdadero cuando se les pide que examinen toda la jerarquía también. P.ej. si instancia de Stringes un Object. Y aquí es Java que es un poco menos intuitivo (porque una instancia en realidad tiene un tipo muy específico) y C # ises más intuitivo (porque cada uno String es unObject profundo).

En pocas palabras: si intenta describir una lógica bastante avanzada en una palabra, seguramente confundirá a pocas personas, de esta manera u otra. Parece que la mayoría de la gente estuvo de acuerdo en un significado y aquellos que no estuvieron de acuerdo, tuvieron que adaptarse.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.