Qué excepciones se deben lanzar para parámetros no válidos o inesperados in.NET?


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

Seguimiento:

¿Qué excepción usaría si tiene una función que espera un entero correspondiente a un mes y pasó en '42'? ¿Caería esto en la categoría" fuera de rango " a pesar de que no es una colección?

Author: Even Mien, 2009-04-21

7 answers

Me gusta usar: ArgumentException, ArgumentNullException, y ArgumentOutOfRangeException.

Hay otras opciones, también, que no se centran tanto en el argumento en sí, sino que juzgan la llamada como una entero:

  • InvalidOperationException – El argumento puede estar bien, pero no en el estado actual del objeto. El crédito va a STW (anteriormente Yooder). Vote su respuesta también.
  • NotSupportedException – Los argumentos pasados son válidos, pero no soportados en esta implementación. Imagine un cliente FTP, y pasa un comando en el que el cliente no es compatible.

El truco es lanzar la excepción que mejor expresa por qué el método no puede ser llamado como es. Idealmente, la excepción debe ser detallada sobre lo que 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 hizo un buen primer paso con sus artículos KB, por ejemplo, "¿Por qué recibo un mensaje de error "Operación abortada" cuando visito una página web en Internet Explorer?". Cuando se encuentra con el error, le apuntan al artículo 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 Yooder) de nuevo por los comentarios.


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

ArgumentOutOfRangeException se lanza cuando se invoca un método y al menos uno de los argumentos pasados a la el método no es nulo referencia (Nothing en Visual Basic) y hace no contiene un valor válido.

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

 212
Author: JoshBerke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:30

He votado por La respuesta de Josh , pero me gustaría añadir una más a la lista:

Sistema.InvalidOperationException debe ser lanzado si el argumento es válido, pero el objeto está en un estado donde el argumento no debe ser usado.

Actualización Tomada de MSDN:

InvalidOperationException se utiliza en casos en que la omisión de invocar un el método es causado por razones distintas a argumentos no válidos.

Digamos que su objeto tiene un Método PerformAction (enmSomeAction action), las enmSomeActions válidas están Abiertas y Cerradas. Si llama a PerformAction (enmSomeAction.Abrir) dos veces seguidas, entonces la segunda llamada debería lanzar la InvalidOperationException (ya que la anulación era válida, pero no para el estado actual del control)

Dado que ya estás haciendo lo correcto programando defensivamente, tengo otra excepción que mencionar es ObjectDisposedException. Si su objeto implementa IDisposable, a continuación, usted siempre debe tener una variable de clase que rastree el estado dispuesto; si su objeto ha sido dispuesto y un método es llamado sobre él, debe levantar la 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 hace un poco más complicada por un tipo de datos genérico (no en el sentido genérico de. NET) que se utiliza para representar un conjunto específico de datos; una enumeración u otro objeto fuertemente tipeado sería un ajuste más ideal--pero no siempre ten ese control.

Personalmente me inclinaría hacia la excepción ArgumentOutOfRangeException y proporcionaría un mensaje que indica que los valores válidos son 1-12. Mi razonamiento es que cuando se habla de meses, suponiendo que todas las representaciones enteras de meses son válidas, entonces se espera un valor en el rango de 1-12. Si solo ciertos meses (como los meses que tenían 31 días) fueran válidos, entonces no se trataría de un Rango per-se y yo lanzaría una excepción genérica ArgumentException que indicó los valores válidos, y también los documentaría en los comentarios del método.

 38
Author: STW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:58

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

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

La respuesta de Yooder me iluminó. Una entrada es no válidosi no es válido en ningún momento, mientras que una entrada es inesperada si no es válida para el estado actual del sistema. Así que en el caso posteriorInvalidOperationException es una elección razonable.

 35
Author: Daniel Brückner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-01 22:39:27

Excepción de argumento.

  • Sistema.ArgumentException
  • Sistema.ArgumentNullException
  • Sistema.ArgumentOutOfRangeException
 4
Author: Syed Tayyab Ali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-21 19:14:20

ArgumentException :

ArgumentException se lanza cuando un método se invoca y al menos uno de los argumentos pasados no cumplen con el parámetro especificación de la llamada método. Todas las instancias de ArgumentException debe llevar un mensaje de error significativo que describe el argumento inválido, así como la rango esperado de valores para el argumento.

Existen también algunas subclases para tipos específicos de invalidez. El enlace tiene resúmenes de los subtipos y cuándo deben aplicarse.

 3
Author: Ben S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-21 19:06:38

Respuesta Corta:
[5]]}

Respuesta más larga:
usar el argumento * Exception (excepto en una biblioteca que es un producto en su on, como la biblioteca de componentes)es un olor. Las excepciones son para manejar situaciones excepcionales, no errores, y no las deficiencias del usuario (es decir, del consumidor de API).

Respuesta más larga:
Lanzar excepciones para argumentos no válidos es grosero, a menos que escriba una biblioteca.
Prefiero usar aserciones, por dos (o más) razones:

  • Las afirmaciones no necesitan ser probadas, mientras que las aserciones de tiro hacen, y la prueba contra ArgumentNullException se ve ridículo (pruébalo).
  • Las afirmaciones comunican mejor el uso previsto de la unidad, y es más cerca de ser ejecutable documentación que un comportamiento de clase especificación.
  • Puede cambiar el comportamiento de violación de aserción. Por ejemplo, en la compilación de depuración, un cuadro de mensaje está bien, por lo que su QA lo golpeará de inmediato (también obtendrá su IDE romper en la línea donde sucede), mientras que en la prueba unitaria puede indicar un error de aserción como un error de prueba.

Aquí es cómo se ve el manejo de la excepción nula (siendo sarcástico, obviamente):

try {
    library.Method(null);
}
catch (ArgumentNullException e) {
    // retry with real argument this time
    library.Method(realArgument);
}

Se utilizarán excepciones cuando se espera una situación pero excepcional (suceden cosas que están fuera del control del consumidor, como la falla de IO). Argumento * Excepción es una indicación de un error y debe ser (mi opinión) manejado con pruebas y asistido con Depurar.Assert

Por cierto: En este caso en particular, podría haber utilizado Month type, en lugar de int. C# se queda corto cuando se trata de seguridad de tipo (Aspecto# rulez!) pero a veces se puede prevenir (o atrapar en tiempo de compilación) esos errores todos juntos.

Y sí, MicroSoft se equivoca al respecto.

 2
Author: THX-1138,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-21 22:40:59

Hay una excepción ArgumentException estándar que puedes usar, o puedes subclase y hacer la tuya propia. Hay varias clases específicas de ArgumentException:

Http://msdn.microsoft.com/en-us/library/system.argumentexception (VS.71).aspx

El que funcione mejor.

 0
Author: Scott M.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-21 19:07:30