Varias respuestas discuten la importancia de los tipos de nullable en general. Hay una respuesta adicional para el booleano anulable, específicamente. Es difícil de entender en C#, pero es muy fácil de entender si observas una lógica de valor nulo en cualquier base de datos.
Digamos que está siguiendo una lista o tabla de Shipments
. A Shipment
tiene un DeliveryDate
, pero por supuesto no conoce esta información hasta mucho después de que se haya realizado el envío, y probablemente al menos unos días después de que el envío se entregó realmente, cuando UPS finalmente se pone a notificarlo. Así que, por supuesto, el DeliveryDate
es un Nullable<DateTime>
(o DateTime?
).
Desea recuperar una lista de todos los envíos que se entregaron durante la última semana. Así se escribe esto:
var deliveredThisWeek = shipments.Where(s =>
s.DeliveryDate >= DateTime.Today.AddDays(-7));
Debería incluirse a los envíos con una fecha de entrega null
? (La respuesta es, por supuesto, no.)
OK, entonces ¿qué pasa con esto:
var deliveredBeforeThisWeek = shipments.Where(s =>
s.DeliveryDate < DateTime.Today.AddDays(-7));
En caso de envíos con una fecha de entrega null
incluirse en estos resultados? La respuesta es todavía no.
Ahora tiene una situación curiosa. Puede pensar que entre las dos consultas, recibirá todos los envíos en el sistema. A | !A
es siempre true
, ¿verdad? No cuando se trata de nulos.
Incluso éste no puede conseguir que todos los resultados:
var deliveredAnytime = shipments.Where(s =>
(s.DeliveryDate >= DateTime.Today.AddDays(-7)) ||
(s.DeliveryDate < DateTime.Today.AddDays(-7)));
Entonces, ¿cómo es esto posible?
Para representar con exactitud esta lógica, necesita una condición que no sea verdadera o false. Y nuevamente, C# es un mal ejemplo aquí porque no implementa la lógica de la manera en que realmente lo esperaría. Pero en SQLese, tiene sentido, porque:
[DeliveryDate >= BeginningOfWeek] = NULL
[DeliveryDate < BeginningOfWeek] = NULL
Claramente, NULL OR NULL
NULL
sigue siendo, no TRUE
. Así es como puede decir correctamente que un envío no se entregó antes del comienzo de la semana, y no se entregó después. O, más exactamente, no sabemos cuando se entregó, por lo que no puede decir con seguridad que hace coincide con cualquiera de esas condiciones.
Pero C# no es tan uniforme. En C#, si el DeliveryDate
es nulo, entonces:
(s.DeliveryDate >= beginningOfWeek) == false
(s.DeliveryDate < endOfWeek) == false
Qué le consigue la respuesta correcta para nuestra consulta anterior, por lo que podría estar tentado a decir que la lógica booleana regular es lo suficientemente bueno, excepto que éste se mete se todo:
var deliveredThisWeek = shipments.Where(s =>
!(s.DeliveryDate < DateTime.Today.AddDays(-7));
Aha ... ahora nos está devolviendo null
fechas de entrega! ¡Esto no está bien! Y antes de que alguien diga "@Aaronaught, ¿en qué estás hablando, por supuesto, ¡esos envíos NO se entregaron antes de la semana pasada, por lo que la condición debería cubrirlos!", detente y piensa en ello por un segundo.
El NULL
en realidad no significa que no se entregaron. El NULL
significa que no sabemos cuando se entregaron. Es posible que un empleado recoja la confirmación mañana y rellene el DeliveryDate
como hace dos semanas, invalidando los datos que acabamos de recoger. Debe no ser instancias nulas que vuelven de esa consulta, y sin embargo existen. Si escribió la misma consulta en SQL, esos resultados se excluirán.
Por lo tanto, ¿Por qué si te importa Nullable<bool>
cuando aparentemente C no?Para que pueda evitar caer en esta trampa en su propio código:
public static bool? IsThisWeek(DateTime? dt)
{
return (dt != null) ? (bool?)(dt.Value > DateTime.Today.AddDays(-7)) : null;
}
var deliveredBeforeThisWeek = shipments.Where(s =>
(!IsThisWeek(s.DeliveryDate) == true));
// Or, the equivalent:
var alsoDeliveredBeforeThisWeek = shipments.Where(s =>
(IsThisWeek(s.DeliveryDate) == false));
Esto es un poco incómodo, pero correcto. Hemos escrito una consulta que más o menos comunica su intención correctamente, y (bool?)null
no equivale a true
ofalse
, por lo que obtenemos los resultados correctos en ambos casos.
Si alguna vez tiene que evaluar una condición en la que la respuesta podría ser "no sé" - usar un bool?
(También conocido como Nullable<bool>
) como resultado.
De esta manera, la persona que llama puede decidir cómo manejar una respuesta "No sé" en lugar de simplemente elegir una opción predeterminada. Cualquier otra cosa significa que su clase es mintiendo.
Para facilitar su búsqueda, ya que buscar un signo de interrogación en Google es una verdadera perra :) El tipo completo es 'Nullable' –
No necesita un tercer valor para 'bool', por lo que solo tiene dos. Pero 'bool?' - es decir, 'Nullable' donde 'T' es' bool' - es una cosa completamente diferente - significa "o este es' nulo', o algún valor del dominio de valor de tipo 'bool'" . –
Esa es la razón por la que SOF no me deja agregar un nuevo bool? ¡¡¡¡etiqueta!!!! –