2011-05-31 5 views
7

Duplicar posible:
C#: Best practice for validating “this” argument in extension methodsElección de diseño: ¿deseo que los métodos de extensión arrojen excepciones en nulo?

estoy ambivalente sobre una opción de diseño, y le gustaría conocer las opiniones de la comunidad SO. El ejemplo que menciono aquí es solo un posible caso en el que se debe hacer esta elección de diseño: en realidad, podría haber muchos más casos. Las respuestas son bienvenidas tanto a este caso específico como a un enfoque más general, y también se agradecen las pautas sobre cómo tomar la decisión en un caso específico.

Básicamente, quiero saber cómo pensar acerca de esto: Al escribir un método de extensión que no falla intrínseca si una referencia nula se pasa como el this ejemplo, se debe realizar una comprobación nula en el argumento o no ?

Ejemplo:

Estoy escribiendo un método de extensión en IEnumerable<T> que recorrer la colección y performe algunos Action<T> - Básicamente, esto es lo que va a hacer:

public static void Each<T>(this IEnumerable<T> collection, Action<T> action) 
{ 
    foreach (var t in collection) 
    { 
     action.Invoke(t); 
    } 
} 

Lo que no puedo decidir es qué debe hacer este método de extensión si se pasa null a cualquiera de los parámetros. Si no agrego ninguna comprobación nula, obtendré un NullReferenceException en action.Invoke(T), pero si collection es null, el bucle for simplemente no hará nada en silencio (y no se lanzará ninguna excepción incluso si action es también action ...).

Estoy bastante decidido a agregar un cheque nulo para action, por lo que puedo lanzar un ArgumentNullException en lugar del NullReferenceException. Pero, ¿qué quiero hacer con el collection?

Opción 1: Agregue un cheque nulo, y arroje ArgumentNullException.

Opción 2: Simplemente deje que el método no haga nada en silencio.

¿Cuál será más útil donde podría querer usar el método en el futuro? ¿Por qué?

+2

Si la colección es nula, también obtendrá una NullReferenceException del bucle foreach. – m0sa

+1

Solo por cierto: sabes que LINQ proporciona un ForAll (o algo por el estilo), que hace exactamente lo que quieres (¿hasta donde puedo ver?). No es que tenga algo que ver con su pregunta, y esto podría ser solo un ejemplo de su parte, pero podría tratar de ver qué hace LINQ-extension-methods cuando los da nulos, y tal vez copie eso. ¿Sigue los patrones de MS cuando escribe C#? – Alxandr

+0

@bzlm: ¿Cómo funciona eso? ¿O es solo para colecciones/enumerables? – Alxandr

Respuesta

12

Microsoft lanza una ArgumentNullException si las colecciones invocadas en LINQ están vacías. Esto es más una cuestión de estilo, pero es consistente con la forma en que se supone que deben comportarse los métodos de extensión.

@ m0sa tiene razón en que obtendrá una referencia nula de su foreach, pero yo diría que revise arriba y lance ArgumentNullException. De esa forma estarás a la par con lo que LINQ hace.

Por ejemplo, si nos fijamos en cualquier() en un decompilador que ver:

public static bool Any<TSource>(this IEnumerable<TSource> source) 
{ 
    if (source == null) 
    { 
     throw Error.ArgumentNull("source"); 
    } 
    using (IEnumerator<TSource> enumerator = source.GetEnumerator()) 
    { 
     if (enumerator.MoveNext()) 
     { 
      return true; 
     } 
    } 
    return false; 
} 
+0

En este ejemplo, esto tiene mucho sentido. Pero ¿qué pasa con '.IsNullOrEmpty()'? En ese caso, realmente no tendría sentido lanzarse en nulo ... ¿Sería entonces una mala práctica para los métodos de extensión? –

0

Primero de todo: estoy bastante seguro de que habrá un NullReferenceException si collection es null. Entonces esa parte de tu pregunta no es problema en absoluto. Respecto al resto: ¿Ganas algo marcando null y lanzando una excepción diferente? En mi opinión: ¡no! Así que no desordenaría mi código con cheques que no ayudan en nada.

+0

El punto de vista opuesto es "Fail Fast", que tiene muchos suscriptores – Greg

2

definitivamente debe hacer null comprobación y tirar ArgumentNullException para evitar difícil de entender NullReferenceExceptions dentro de su código.

En general, evitaría tratar null como en "vacío" IEnumerable<T>. Solo use Enumerable.Empty<T>() para evitar casos especiales para una colección null.

Si decide hacer null comprobando en su método de extensión debería considerar hacerlo "con entusiasmo". Si está utilizando yield return dentro de su método de extensión, nada de esto se evaluará hasta que comience la iteración. Usted divide su método de extensión en dos partes. La parte "ansiosa" donde se verifican los argumentos y los elementos "vagos" que yield return.

0

Si el argumento de recopilación fue null arrojaría un NullReferenceException. Esto viene de pensar en cómo se comportaría si fuera null, y Each<T> pasó a ser simplemente un método normal - un NullReferenceException siendo lanzado es lo que esperaría que sucediera.

EDIT: Basándome en el comentario de Martin y en algunas investigaciones adicionales sobre esto, recupero lo que dije. Parece que un NullReferenceExceptionshouldn't be thrown in this case, como Microsoft recommends using an ArgumentNullException instead.

+0

No se supone que arrojes una 'NullReferenceException' de tu código. El tiempo de ejecución lo arrojará si se desreferencia una referencia 'null'. Si quieres evitar eso (muchos lo hacen) debes verificar los argumentos del método y lanzar 'ArgumentNullException' si es necesario. –

+0

@Martin Liversage: Sí, [parece que es correcto] (http://blogs.msdn.com/b/jaredpar/archive/2010/06/28/do-not-throw-a-nullreferenceexception-when-validing- this-in-an-extension-method.aspx). Mi error. – ataddeini

Cuestiones relacionadas