¿Qué excepciones se deben generar para parámetros no válidos o inesperados en .NET?

Resuelto Even Mien asked hace 15 años • 7 respuestas

¿Qué tipos de excepciones deberían generarse para parámetros no válidos o inesperados en .NET? ¿Cuándo elegiría uno en lugar de otro?

Hacer un seguimiento:

¿Qué excepción usarías si tienes una función que espera un número entero correspondiente a un mes y pasas '42'? ¿Caería esto en la categoría "fuera de rango" aunque no sea una colección?

Even Mien avatar Apr 22 '09 02:04 Even Mien
Aceptado

Me gusta usar: ArgumentException, ArgumentNullExceptiony ArgumentOutOfRangeException.

  • ArgumentException– Algo anda mal con el argumento.
  • ArgumentNullException– El argumento es nulo.
  • ArgumentOutOfRangeException– No uso mucho este, pero un uso común es indexar en una colección y dar un índice demasiado grande.

También hay otras opciones que no se centran tanto en el argumento en sí, sino que juzgan la convocatoria en su conjunto:

  • InvalidOperationException– El argumento puede estar bien, pero no en el estado actual del objeto. El crédito es para STW (anteriormente Yoooder). Vota su respuesta también.
  • NotSupportedException– Los argumentos pasados ​​son válidos, pero no son compatibles con esta implementación. Imagine un cliente FTP y le pasa un comando que el cliente no admite.

El truco consiste en generar la excepción que mejor exprese por qué no se puede llamar al método tal como está. Idealmente, la excepción debería detallar qué salió mal, por qué está mal y cómo solucionarlo.

Me encanta cuando los mensajes de error apuntan a ayuda, documentación u otros recursos. Por ejemplo, Microsoft dio un buen primer paso con sus artículos de KB, por ejemplo "¿Por qué recibo un mensaje de error de "Operación cancelada" cuando visito una página web en Internet Explorer?" . Cuando encuentre el error, le indicarán el artículo de KB en el mensaje de error. Lo que no hacen bien es que no te dicen por qué específicamente falló.

Gracias a STW (ex Yoooder) nuevamente por los comentarios.


En respuesta a su seguimiento, lanzaría un ArgumentOutOfRangeException. Mire lo que dice MSDN sobre esta excepción:

ArgumentOutOfRangeExceptionse lanza cuando se invoca un método y al menos uno de los argumentos pasados ​​al método no es una referencia nula ( Nothingen Visual Basic) y no contiene un valor válido.

Entonces, en este caso, estás pasando un valor, pero ese no es un valor válido, ya que tu rango es 1–12. Sin embargo, la forma en que lo documenta deja claro lo que arroja su API. Porque aunque podría decirlo yo ArgumentOutOfRangeException, podría decirlo otro desarrollador ArgumentException. Hágalo fácil y documente el comportamiento.

JoshBerke avatar Apr 21 '2009 19:04 JoshBerke

Voté por la respuesta de Josh , pero me gustaría agregar una más a la lista:

Se debe generar System.InvalidOperationException si el argumento es válido, pero el objeto se encuentra en un estado en el que el argumento no debe usarse.

Actualización tomada de MSDN:

InvalidOperationException se utiliza en los casos en que la falla al invocar un método se debe a razones distintas a los argumentos no válidos.

Digamos que su objeto tiene un método PerformAction (acción enmSomeAction), las enmSomeActions válidas son Abrir y Cerrar. Si llama a PerformAction(enmSomeAction.Open) dos veces seguidas, la segunda llamada debería generar InvalidOperationException (ya que el argumento era válido, pero no para el estado actual del control).

Como ya estás haciendo lo correcto al programar de manera defensiva, tengo otra excepción que mencionar: ObjectDisposedException. Si su objeto implementa IDisposable, entonces siempre debe tener una variable de clase que rastree el estado desechado; Si su objeto ha sido eliminado y se llama a un método, debe generar la excepción ObjectDisposedException:

public void SomeMethod()
{
    If (m_Disposed) {
          throw new ObjectDisposedException("Object has been disposed")
     }
    // ... Normal execution code
}

Actualización: Para responder a su seguimiento: Es una situación un poco ambigua y se complica un poco más por el uso de un tipo de datos genérico (no en el sentido de .NET Generics) para representar un conjunto específico de datos; una enumeración u otro objeto fuertemente tipado sería una opción más ideal, pero no siempre tenemos ese control.

Personalmente, me inclinaría por ArgumentOutOfRangeException y proporcionaría un mensaje que indique que los valores válidos son del 1 al 12. Mi razonamiento es que cuando se habla de meses, asumiendo que todas las representaciones enteras de meses son válidas, se espera un valor en el rango de 1 a 12. Si solo ciertos meses (como meses que tenían 31 días) fueran válidos, entonces no estaría tratando con un Rango per se y arrojaría una ArgumentException genérica que indica los valores válidos, y también los documentaría en los comentarios del método.

STW avatar Apr 21 '2009 19:04 STW

Dependiendo del valor real y de qué excepción se ajusta mejor:

  • ArgumentException(algo anda mal con el valor)

  • ArgumentNullException(el argumento es nulo mientras esto no esté permitido)

  • ArgumentOutOfRangeException(el argumento tiene un valor fuera del rango válido)

Si esto no es lo suficientemente preciso, simplemente derive su propia clase de excepción de ArgumentException.

La respuesta de Yoooder me iluminó. Una entrada no es válida si no es válida en ningún momento, mientras que una entrada es inesperada si no es válida para el estado actual del sistema. Entonces, en el último caso, an InvalidOperationExceptiones una opción razonable.

Daniel Brückner avatar Apr 21 '2009 19:04 Daniel Brückner