En VB.NET esto sucede:
Dim x As System.Nullable(Of Decimal) = Nothing
Dim y As System.Nullable(Of Decimal) = Nothing
y = 5
If x <> y Then
Console.WriteLine("true")
Else
Console.WriteLine("false") '' <-- I got this. Why?
End If
Pero en C # sucede esto:
decimal? x = default(decimal?);
decimal? y = default(decimal?);
y = 5;
if (x != y)
{
Debug.WriteLine("true"); // <-- I got this -- I'm with you, C# :)
}
else
{
Debug.WriteLine("false");
}
¿Por qué hay una diferencia?
default(decimal?)
devuelve 0, nonull
.null
If
condicionales no requieren evaluar como un booleano ... uuuugh EDIT: Entonces, loNothing <> Anything = Nothing
que resulta enIf
tomar la ruta negativa / else.Respuestas:
VB.NET y C # .NET son lenguajes diferentes, creados por diferentes equipos que han hecho diferentes suposiciones sobre el uso; en este caso la semántica de una comparación NULL.
Mi preferencia personal es por la semántica de VB.NET, que en esencia le da a NULL la semántica "No lo sé todavía". Luego, la comparación de 5 con "Todavía no lo sé". es naturalmente "no lo sé todavía"; es decir, NULO. Esto tiene la ventaja adicional de reflejar el comportamiento de NULL en (la mayoría, si no todas) las bases de datos SQL. Esta es también una interpretación más estándar (que la de C #) de la lógica de tres valores, como se explica aquí .
El equipo de C # hizo diferentes suposiciones sobre lo que significa NULL, lo que resultó en la diferencia de comportamiento que muestra. Eric Lippert escribió un blog sobre el significado de NULL en C # . Según Eric Lippert: "También escribí sobre la semántica de nulos en VB / VBScript y JScript aquí y aquí ".
En cualquier entorno en el que sean posibles valores NULL, es importante reconocer que ya no se puede confiar en la Ley del Medio Excluido (es decir, que A o ~ A es tautológicamente verdadera).
Actualizar:
A
bool
(a diferencia de abool?
) solo puede tomar los valores VERDADERO y FALSO. Sin embargo, una implementación de lenguaje de NULL debe decidir cómo se propaga NULL a través de expresiones. En VB, las expresiones5=null
y5<>null
AMBAS devuelven falso. En C #, de las expresiones comparables5==null
y5!=null
solo lasegundaprimera [actualizado 2014-03-02 - PG] devuelve falso. Sin embargo, en CUALQUIER entorno que admita nulos, es responsabilidad del programador conocer las tablas de verdad y la propagación de nulos utilizadas por ese lenguaje.Actualizar
Los artículos del blog de Eric Lippert (mencionados en sus comentarios a continuación) sobre semántica están ahora en:
30 de septiembre de 2003 - Un montón de nada
1 de octubre de 2003 - Un poco más sobre nada
fuente
bool
no se pueden tener 3 valores, solo dos. Esbool?
que puede tener tres valores.operator ==
yoperator !=
ambos devuelvenbool
, nobool?
, independientemente del tipo de operandos. Además, unaif
declaración solo puede aceptar unbool
, no unbool?
.5=null
y5<>null
no son válidas. Y de5 == null
y5 != null
, ¿estás seguro de que es el segundo que vuelvefalse
?Porque
x <> y
devuelve enNothing
lugar detrue
. Simplemente no está definido yax
que no está definido. (similar a SQL nulo).Nota: VB.NET
Nothing
<> C #null
.También debe comparar el valor de a
Nullable(Of Decimal)
solo si tiene un valor.Entonces, el VB.NET anterior se compara de manera similar a esto (que parece menos incorrecto):
La especificación del lenguaje VB.NET :
Por ejemplo:
fuente
Mira el CIL generado (he convertido ambos a C #):
C#:
Visual Basic:
Verá que la comparación en Visual Basic devuelve Nullable <bool> (¡no bool, falso o verdadero!). Y undefined convertido a bool es falso.
Nothing
comparado con lo que sea siempreNothing
, no falso en Visual Basic (es lo mismo que en SQL).fuente
El problema que se observa aquí es un caso especial de un problema más general, que es que el número de diferentes definiciones de igualdad que pueden ser útiles en al menos algunas circunstancias excede el número de medios comúnmente disponibles para expresarlas. En algunos casos, este problema se agrava por la desafortunada creencia de que es confuso que diferentes medios para probar la igualdad den resultados diferentes, y tal confusión podría evitarse haciendo que las diferentes formas de igualdad produzcan los mismos resultados siempre que sea posible.
En realidad, la causa fundamental de confusión es una creencia equivocada de que se debe esperar que las diferentes formas de prueba de igualdad y desigualdad produzcan el mismo resultado, a pesar del hecho de que diferentes semánticas son útiles en diferentes circunstancias. Por ejemplo, desde un punto de vista aritmético, es útil poder hacer que los
Decimal
que difieren solo en el número de ceros finales se comparen como iguales. Lo mismo ocurre condouble
valores como cero positivo y cero negativo. Por otro lado, desde el punto de vista del almacenamiento en caché o internación, esta semántica puede ser mortal. Supongamos, por ejemplo, que uno tuviera unDictionary<Decimal, String>
tal quemyDict[someDecimal]
debería ser igualsomeDecimal.ToString()
. Tal objeto parecería razonable si uno tuviera muchosDecimal
valores que uno quería convertir en cadena y esperaba que hubiera muchos duplicados. Desafortunadamente, si se utiliza este almacenamiento en caché para convertir 12,3 my 12,40 m, seguidos de 12,30 my 12,4 m, estos últimos valores producirían "12,3" y "12,40" en lugar de "12,30" y "12,4".Volviendo al tema que nos ocupa, hay más de una forma sensata de comparar la igualdad de objetos que aceptan valores NULL. C # adopta el punto de vista de que su
==
operador debería reflejar el comportamiento deEquals
. VB.NET adopta el punto de vista de que su comportamiento debería reflejar el de algunos otros lenguajes, ya que cualquiera que desee elEquals
comportamiento podría utilizarEquals
. En cierto sentido, la solución correcta sería tener una construcción "si" de tres vías y requerir que si la expresión condicional devuelve un resultado de tres valores, el código debe especificar qué debería suceder en elnull
caso. Dado que esa no es una opción con los idiomas como son, la siguiente mejor alternativa es simplemente aprender cómo funcionan los diferentes idiomas y reconocer que no son iguales.Por cierto, el operador "Is" de Visual Basic, que carece de C, se puede usar para probar si un objeto que acepta valores NULL es, de hecho, nulo. Si bien uno podría cuestionar razonablemente si una
if
prueba debería aceptar aBoolean?
, es una característica útil que los operadores de comparación normales regresen enBoolean?
lugar deBoolean
cuando se invocan en tipos que aceptan valores NULL. Por cierto, en VB.NET, si uno intenta usar el operador de igualdad en lugar deIs
, recibirá una advertencia de que el resultado de la comparación siempre seráNothing
, y debe usarloIs
si desea probar si algo es nulo.fuente
== null
. Y probar si un tipo de valor que acepta valores NULL tiene un valor se realiza mediante.hasValue
. ¿De qué sirve unIs Nothing
operador? C # tiene,is
pero prueba la compatibilidad de tipos. A la luz de estos, realmente no estoy seguro de lo que intenta decir su último párrafo.null
, aunque ambos lenguajes lo tratan como azúcar sintáctico para unaHasValue
verificación, al menos en los casos en que se conoce el tipo (no estoy seguro qué código se genera para los genéricos).Puede ser que esta publicación te ayude:
Si mal no recuerdo, "Nada" en VB significa "el valor predeterminado". Para un tipo de valor, ese es el valor predeterminado, para un tipo de referencia, sería nulo. Por tanto, no asignar nada a una estructura no supone ningún problema.
fuente
<>
operador en VB y cómo opera en tipos que aceptan valores NULL.Esta es una rareza definida de VB.
En VB, si desea comparar dos tipos que aceptan valores NULL, debe usar
Nullable.Equals()
.En su ejemplo, debería ser:
fuente
Nullable<>.Equals()
. Uno podría esperar que funcione de la misma manera (que es lo que hace C #).Nullable
no existía en las primeras versiones de .NET, se creó después de que C # y VB.NET estuvieron fuera durante algún tiempo y ya determinaron su comportamiento de propagación nula. ¿Honestamente espera que el lenguaje haya sido consistente con un tipo que no se habrá creado durante varios años? Desde el punto de vista de un programador de VB.NET, es Nullable. Equals que no es consistente con el lenguaje, y no al revés. (Dado que C # y VB usan la mismaNullable
definición, no había forma de que fuera consistente con ambos lenguajes).Su código VB es simplemente incorrecto - si cambia "x <> y" a "x = y" todavía tendrá "falso" como resultado. La forma más común de expresar esto para instancias que aceptan valores NULL es "Not x.Equals (y)", y esto producirá el mismo comportamiento que "x! = Y" en C #.
fuente
x
seanothing
, en cuyo casox.Equals(y)
se lanzará una excepción.