2010-07-12 11 views
6

Recientemente estoy desarrollando un software que analiza y muestra información XML desde un sitio web. Lo suficientemente simple ¿verdad?Parece que he tenido algunos problemas masivos y masivos con NullReferenceExceptions

Obtengo LOADS de NullReferenceExceptions. Por ejemplo, este método:

private void SetUserFriends(List<Friend> list) 
{ 
    int x = 40; 
    int y = 3; 

    if (list != null) 
    { 
     foreach (Friend friend in list) 
     { 
      FriendControl control = new FriendControl(); 
      control.ID = friend.ID; 
      control.URL = friend.URL; 
      control.SetID(friend.ID); 
      control.SetName(friend.Name); 
      control.SetImage(friend.Photo); 

      control.Location = new Point(x, y); 
      panel2.Controls.Add(control); 

      y = y + control.Height + 4; 
     } 
    } 
} 

tuve que envolver un feo como el pecado Si todo el bucle foreach real con el fin de prevenir una excepción.

Siento que solo estoy colocando tiritas en un neumático pinchado en lugar de solucionar el problema. ¿Hay alguna manera de abordar este problema? ¿Tal vez un libro que debería leer sobre los patrones de programación o qué no?

Realmente, estoy perdido. Probablemente estoy haciendo las preguntas incorrectas.

+8

Debería estar mirando el código que está * llamando * 'SetUserFriends'. Si asumes que la lista de amigos no debería ser 'null' (lo cual es una suposición bastante buena, diría), entonces el error está en lo que esté pasando * en *' nulo'. Use el depurador para buscar la pila de llamadas cuando obtenga la excepción. –

+1

Mejor compruebe por qué tiene una referencia de lista nula en lugar de un objeto de lista vacío. – BenV

+3

Esta es una nota al margen, pero yo abogaría por aceptar IEnumerable , de modo que el método no requiera que la persona que llama use una clase de colección particular. –

Respuesta

15

Parece que no está seguro de qué hacer si recibe malos parámetros en sus métodos. No hay nada inherentemente malo en lo que estás haciendo ahora, pero el patrón más común es comprobar los parámetros en la cabecera de su método, lanzar una excepción si no son lo que te esperas:

if (list == null) 
{ 
    throw new ArgumentNullException(list); 
} 

Este es un patrón de programación defensiva común: verifique para asegurarse de que los datos que le proporcionen pasen verificaciones básicas de cordura.

Ahora, si está llamando a este método explícitamente usted mismo, y está encontrando que este método recibe un parámetro list nulo cuando no lo está esperando, es hora de mirar la lógica del método de llamada. Yo prefiero pasar una lista vacía cuando no tengo elementos, a diferencia de null, para evitar casos especiales como este.

+0

+1 Si haces esto constantemente, aprenderás cómo escribir código que evite nulos involuntarios. –

+1

+1 para programación defensiva –

4

probablemente voy a conseguir downvoted por la multitud "no hay salida múltiple" pero por lo general manejar eso con una simple verificación justo al principio del método:

if (list == null || list.Count == 0) return; 

esto especifica las condiciones de salida y entonces no necesita preocuparse por los niveles múltiples de sangría en su método. Esto solo funciona si puede permitirse tragar el hecho de que su lista es nula o está vacía, lo que puede suceder en algunos casos.

Pero estoy de acuerdo con codeka, ya que necesita mirar el código de llamada y averiguar si puede mejorar desde allí.

+4

Este enfoque * podría * funcionar para este caso específico, pero en general conduce a errores muy sutiles. La mayoría de las veces no podemos inferir razonablemente lo que la persona que llama pretendió pasar 'null', por lo que es más seguro abortar con una excepción. –

+2

Debe documentarse si un método acepta nulo o no (e idealmente) lo que hace si no se cumple esta condición previa. Estoy de acuerdo con @Rex en que los retornos silenciosos a menudo pueden dañar la depuración. –

+0

Estoy completamente de acuerdo con ambos, pero hay casos en los que puede ser útil –

0

Volvería temprano (o arrojaría una InvalidArgumentException anticipadamente) cuando se le dé una entrada no válida.

Por ejemplo:

private void SetUserFriends(List<Friend> list) 
{ 
    if (list == null) 
     return; 

    /* Do stuff */ 
} 

Alternativamente, puede utilizar el patrón nula general de coalescencia:

private void SetUserFriends(List<Friend> list) 
{ 
    list = list ?? new List<Friend>(); 

    /* Do Stuff */ 
} 
+1

Sin embargo, la sugerencia de coalescencia nula es un poco ridícula para este escenario. –

+1

Regresar temprano y lanzar son * extremadamente * enfoques diferentes. ¿Qué recomiendas? –

+0

Uhm, si va a lanzar una excepción, la correcta sería 'ArgumentNullException', como lo mostró el ejemplo de Michael. –

1

Además de lanzar excepciones ArgumentNullException También hay algo llamado el "patrón nulo Obejct", que se puede use si quiere que pase alrededor de un valor nulo, para indicar, por ejemplo, que algo no existe, pero no desea tener que buscar nulos explícitamente. Esencialmente es una clase de stub que implementa la misma interfaz, pero sus métodos generalmente están vacíos o devuelven solo lo suficiente para que sean completos. http://en.wikipedia.org/wiki/Null_Object_pattern

También es útil para los tipos de valores que no pueden expresar fácilmente su inexistencia, al no ser nulo.

+0

Interesante, pero no estoy seguro de si se aplica aquí, ya que lo más parecido al patrón de objeto nulo aquí sería mantener una lista vacía. El otro problema, que señalé en otro lugar, es que este método probablemente debería aceptar un IEnumerable en lugar de una Lista. –

+0

Es cierto, pero mencionó que esto es simplemente un ejemplo de sus "CARGAS de NullReferenceExceptions". Puede ser la solución correcta para algunos de sus otros. Para este, lanzaría la excepción también. – Spike

+0

Mi impresión aquí es que esto es menos una cuestión de olvidar comprobar nulo y más una cuestión de no tener idea de por qué fue nulo en primer lugar. El objetivo del patrón de objeto nulo es evitar las comprobaciones nulas, pero no proporcionará ninguna información sobre el problema más profundo aquí. Las excepciones serían, sin embargo, porque frenarían la propagación de valores nulos, haciendo que sea más fácil seguir la traza de la pila hasta donde haya un null snuck. –

2

Parece que la programación defensiva y la validación de parámetros es lo que está buscando.

Como han dicho otros, la validación de parámetros simple podría funcionar para usted:

if (list == null) 
    throw new ArgumentNullException("list"); 

Alternativamente, si se cansa de escribir constantemente cheques como esto para cada parámetro, se puede consultar uno de los de código abierto muchos. NET bibliotecas de ejecución de condiciones previas. Me gusta CuttingEdge.Conditions.

De esta manera, se puede usar algo como esto:

Condition.Requires(list, "list").IsNotNull(); 

Sin embargo, la creación de una condición previa como cualquiera de los anteriores se acaba de especificar que el método no acepta valores nulos. Su problema seguirá existiendo en el que es pasando nulos en el método! Para solucionarlo, deberá examinar qué es lo que llama a sus métodos, y averiguar por qué se están transfiriendo objetos nulos.

+0

+1 para centrarse en la causa raíz. –

+1

Y +1 para hacer referencia a CuttingEdge.Conditions ;-) – Steven

0

De hecho, está haciendo una pregunta incorrecta. La pregunta correcta es "nulo representa una entrada no válida o una bandera que significa X".

Hasta tipos de referencia no nulos se añaden a la lengua y hacer su camino de varias API, usted tiene la opción de hacer que explícita en el código o dejar excepciones referencia nula que encuentres donde se viola la expectativa y luego fijar el datos/código de una manera u otra.

Cuestiones relacionadas