valores valor validar utilice tipo tener que puede objeto nulo net fecha debe dato convertir asignar acepte acepta c# null

valor - validar fecha null en c#



C#está bien al comparar tipos de valores con nulos (9)

Me encontré con esto hoy y no tengo idea de por qué el compilador de C # no está arrojando un error.

Int32 x = 1; if (x == null) { Console.WriteLine("What the?"); }

Estoy confundido sobre cómo x alguna vez podría ser nulo. Especialmente porque esta asignación definitivamente arroja un error de compilación:

Int32 x = null;

¿Es posible que x se vuelva nulo? ¿Microsoft simplemente decidió no colocar esta verificación en el compilador o se perdió por completo?

Actualización: después de jugar con el código para escribir este artículo, de repente el compilador apareció con una advertencia de que la expresión nunca sería cierta. Ahora estoy realmente perdido. Puse el objeto en una clase y ahora la advertencia se ha ido pero se fue con la pregunta, ¿puede un tipo de valor ser nulo?

public class Test { public DateTime ADate = DateTime.Now; public Test () { Test test = new Test(); if (test.ADate == null) { Console.WriteLine("What the?"); } } }


Creo que la mejor respuesta sobre por qué el compilador acepta esto es para las clases genéricas. Considere la siguiente clase ...

public class NullTester<T> { public bool IsNull(T value) { return (value == null); } }

Si el compilador no aceptara comparaciones con null para los tipos de valor, esencialmente rompería esta clase, con una restricción implícita asociada a su parámetro de tipo (es decir, solo funcionaría con tipos no basados ​​en el valor).


El hecho de que una comparación nunca puede ser cierta no significa que sea ilegal. Sin embargo, no, un tipo de valor puede ser null alguna vez.


Esto es legal porque la resolución de sobrecarga del operador tiene un mejor operador único para elegir. Hay un operador == que toma dos entradas anulables. El int local es convertible a un int nullable. El literal nulo es convertible a un int nullable. Por lo tanto, este es un uso legal del operador ==, y siempre dará como resultado falso.

Del mismo modo, también te permitimos decir "if (x == 12.6)", que también siempre será falso. El int local es convertible a doble, el literal es convertible a doble, y obviamente nunca serán iguales.


No es un error, ya que hay una conversión ( int? ); genera una advertencia en el ejemplo dado:

El resultado de la expresión es siempre ''falso'' ya que un valor de tipo ''int'' nunca es igual a ''nulo'' de tipo ''int'' ''

Si marca el IL, verá que elimina completamente la rama inalcanzable, no existe en una compilación de lanzamiento.

Sin embargo, tenga en cuenta que no genera esta advertencia para estructuras personalizadas con operadores de igualdad. Solía ​​en 2.0, pero no en el compilador 3.0. El código aún se elimina (por lo que sabe que el código no está disponible), pero no se genera ninguna advertencia:

using System; struct MyValue { private readonly int value; public MyValue(int value) { this.value = value; } public static bool operator ==(MyValue x, MyValue y) { return x.value == y.value; } public static bool operator !=(MyValue x, MyValue y) { return x.value != y.value; } } class Program { static void Main() { int i = 1; MyValue v = new MyValue(1); if (i == null) { Console.WriteLine("a"); } // warning if (v == null) { Console.WriteLine("a"); } // no warning } }

Con el IL (para Main ), tenga en cuenta que se ha eliminado todo, excepto MyValue(1) (que podría tener efectos secundarios):

.method private hidebysig static void Main() cil managed { .entrypoint .maxstack 2 .locals init ( [0] int32 i, [1] valuetype MyValue v) L_0000: ldc.i4.1 L_0001: stloc.0 L_0002: ldloca.s v L_0004: ldc.i4.1 L_0005: call instance void MyValue::.ctor(int32) L_000a: ret }

esto es básicamente:

private static void Main() { MyValue v = new MyValue(1); }



Sospecho que el compilador optimiza la prueba en particular cuando genera el IL ya que la prueba nunca será falsa.

Nota al margen: ¿Es posible tener un Int32 nulo que use Int32? x en su lugar.


Supongo que esto se debe a que "==" es un azúcar de sintaxis que en realidad representa una llamada al método System.Object.Equals que acepta el parámetro System.Object . La especificación NULL by ECMA es un tipo especial que, por supuesto, deriva de System.Object .

Es por eso que solo hay una advertencia.


Un tipo de valor no puede ser null , aunque podría ser igual a null (considere Nullable<> ). En su caso, la variable int y null se Nullable<Int32> implícitamente en Nullable<Int32> y se comparan.


[EDITADO: hizo advertencias sobre errores e hizo explícitos a los operadores sobre anulables en lugar del hack de cadenas.]

Según la sugerencia inteligente de @ supercat en un comentario anterior, las siguientes sobrecargas del operador le permiten generar un error sobre las comparaciones de su tipo de valor personalizado a nulo.

Mediante la implementación de operadores que se comparan con las versiones anulables de su tipo, el uso de null en una comparación coincide con la versión anulable del operador, que le permite generar el error a través del atributo Obsoleto.

Hasta que Microsoft nos devuelva nuestra advertencia del compilador, voy con esta solución, ¡gracias @supercat!

public struct Foo { private readonly int x; public Foo(int x) { this.x = x; } public override string ToString() { return string.Format("Foo {{x={0}}}", x); } public override int GetHashCode() { return x.GetHashCode(); } public override bool Equals(Object obj) { return x.Equals(obj); } public static bool operator ==(Foo a, Foo b) { return a.x == b.x; } public static bool operator !=(Foo a, Foo b) { return a.x != b.x; } [Obsolete("The result of the expression is always ''false'' since a value of type ''Foo'' is never equal to ''null''", true)] public static bool operator ==(Foo a, Foo? b) { return false; } [Obsolete("The result of the expression is always ''true'' since a value of type ''Foo'' is never equal to ''null''", true)] public static bool operator !=(Foo a, Foo? b) { return true; } [Obsolete("The result of the expression is always ''false'' since a value of type ''Foo'' is never equal to ''null''", true)] public static bool operator ==(Foo? a, Foo b) { return false; } [Obsolete("The result of the expression is always ''true'' since a value of type ''Foo'' is never equal to ''null''", true)] public static bool operator !=(Foo? a, Foo b) { return true; } }