2010-07-19 10 views
10

Acabo de comenzar a escribir sobre un componente donde encontré que podría ser útil declarar algunas de las propiedades con nulo, en lugar de dejar que recurran a valores predeterminados. Sin embargo, me di cuenta de que nunca antes había usado la sintaxis non-nullable-type? o el tipo Nullable<T> antes, por lo que probablemente haya algunos errores que pronto saldrán y me morderán. Así que ...Gotchas al hacer uso de Nullable <T> en C# 4

  • ¿Cuáles son las mayores trampas al usar Nullable<T> y la sintaxis abreviada ??

  • ¿Cómo puedo solucionarlos?

  • ¿Cuáles son las mayores ventajas/nuevas posibilidades que tengo disponibles cuando comienzo a usarlas?

+9

escribir el código. Vuelve cuando explote. No es ciencia espacial. –

+3

@Hans, no estoy de acuerdo: no es malo intentar anticipar problemas ... Estoy seguro de que las respuestas serían útiles para mucha gente –

+0

@Closers: me doy cuenta de que tendré que volver a la comunidad cuando tengo un problema "real", pero dado que este es un concepto completamente nuevo, no pensé que me perjudicaría obtener ayuda para explorar el terreno. Si este concepto no es muy difícil, entonces tal vez estoy siendo demasiado cauteloso, pero podría haber sido una de esas áreas en las que estás obligado a cometer errores de novato, y donde pueden ser muy difíciles de detectar. La respuesta de Mark Byers es un excelente ejemplo de las cosas que estaba buscando. –

Respuesta

18

Un error común es intentar asignar a una variable anulable con una expresión condicional como sigue:

bool useDefault = true; 
int defaultValue = 50; 
int? y = useDefault ? defaultValue : null; 

A primera vista esto puede parecer que debería funcionar, pero en realidad da un error de compilación:

 
Type of conditional expression cannot be determined because there is no 
implicit conversion between 'int' and '<null>' 

Solución: añadir un fundido a uno o ambos de los posibles resultados:

int? y = useDefault ? defaultValue : (int?)null; 

Menos comúnmente visto: Normalmente es seguro asumir que para los enteros y a <= 5!(a > 5) son equivalentes. Esta suposición no es verdadera para enteros nulables.

int? x = null; 
Console.WriteLine(x <= 5); 
Console.WriteLine(!(x > 5)); 

Resultado:

 
False 
True 

Solución: Controle el nulo caso por separado.


Aquí hay otro ligera variación de lo anterior:

int? y = null; 
int? z = null; 
Console.WriteLine(y == z); 
Console.WriteLine(y <= z); 

Salida:

 
True 
False 

Así y es igual a z, pero no es menor o igual a z.

Solución: Una vez más, el tratamiento el caso nulo separado puede evitar sorpresas.

+0

Entity Framework me enseñó mucho sobre los tipos anulables – msarchet

1

que puede hacer .HasValue para comprobar si la variable es nula

se puede hacer

myvar = nullablevar ?? defaultvalue; //will set defaultvalue if nullablevar is null 

y mucho más, no es nuevo en C# 4

read this for more information

+0

No es realmente un "gotcha", pero MUY útil para saber –

0

No estoy utilizando actual 4.0, pero en 2.0 tengo el problema de que, como la mayoría de los genéricos, int? no se puede deserializar fácilmente Tal vez 4.0 es más inteligente con Reflection, pero las utilidades de serializador XML predeterminadas no pueden leerlo y está expuesto. Es bastante molesto

+0

No sé si fue diferente en 2.0, pero en 4.0 la serialización de tipos genéricos a XML no es un problema en absoluto. .. serializar un 'Foo ' da como resultado un elemento '' en XML –

+0

En 2.0, obtengo un error de reflexión del deserializador XML (solo uso el predeterminado) usando cualquier propiedad o campo genérico. Tengo que enhebrar [] o ArrayList porque la lista no se serializará/deserializará. Si esto está arreglado en 4.0, mi corazón cantará con alegría. Trabajar en código heredado apesta. –

0

Establezca el valor predeterminado de forma inconsciente mientras usa las nullas. Lo he visto algunas veces P.ej.

int? localVar = 0; 
// do something .. 
if (localVar.HasValue) 
    _myMemberValue = localVar.Value; 

El LocalVar nunca es nula porque era inicializar con un valor por lo que la prueba para HasValue es alwasy verdadera y _myMemberValue puede asignado incorrectamente con valor incorrecto.

- editied, para añadir más comentarios ----

se olvidó de mencionar. Una gran ventaja que he visto es usar el campo para representar el campo Nullable en la base de datos. Esto también se genera automáticamente si usa Linq y EF. Pero tradicionalmente antes de Nullable, es un trabajo manual y propenso a errores manejar la actualización del campo y decidir cuándo establecerlo con un valor o nulo.

1

Nullable<T> es un tipo de valor especial. Podría ayudar si entiendes cómo funciona realmente. Hay algunas cosas sutiles que no son inmediatamente obvias. Publiqué en el blog acerca de here.

Complicaciones reales: no muchas. Casi el más grande es que el lanzamiento explícito arroja un InvalidOperationException (y no NullReferenceException). El compilador debe guiarlo por cualquier problema que pueda surgir.

1

Nullable<T> tipos son un poco inusual; no son (estrictamente hablando) ni valores ni tipos de referencia, sino algo extraño en el medio. El boxeo/unboxing y typeof en particular tienen reglas especiales por lo que los resultados son menos inesperados.

Para más detalles, recomiendo el libro de Jon Skeet C# in Depth. Si aún no lo posee, debería hacerlo. :)

10

Algo a lo que la gente suele sorprenderse es que no existe el tipo de valor que admite valores nulos. Si usted dice:

int? x = 123; 
int? y = null; 
int z = 456; 
object xx = x; 
object yy = y; 
object zz = z; 

se podría pensar que ya contiene un zz int caja, que contienen xx e yy en caja enteros con valores nulos. Ellos no. xx contiene un int en caja yy está configurado como nulo.

1

Uno de los mejores usos es que los mapas bastante bien a los campos de base de datos con valores nulos - Teniendo esto en mente, que desea utilizar como si fuera un campo nulo en una base de datos.

Es decir, un valor nulo no es "otro" - significa desconocido, o incalculable en este momento, o que dados otros valores en este objeto/registro, no tiene sentido que esto sea un valor .Su situación suena como que es válida - las preferencias del usuario puede ser nulo, y los valores reales serán

actualValue = userValue ?? defaultValue; 

El ?? es el operador nula coalescencia - lo anterior es equivalente a la siguiente:

actualValue = userValue.HasValue ? userValue : defaultValue; 

o

actualValue = (userValue != null) ? userValue : defaultValue; 

La tentación veo gente da en lo más a menudo se utiliza como un indicador bool? tri-estatal. Esto no tiene sentido, porque no hay una tercera posibilidad en verdadero/falso/??? Otros que lean tu código tendrán que profundizar en los comentarios (el mejor de los casos) para descubrir que true significa usar texto azul, falso significa texto rojo y nulo significa texto verde. Use enumeraciones para esto.

Esa es la trampa más grande que veo la gente cae en - aparte de eso, simplemente acostumbrarse a comprobar si sus nullables son nulos - ya sea mediante su comparación con un valor nulo o mediante el uso de .HasValue

+0

+1 para la nota sobre 'bool?' Como bandera de tres estados =) –