tipos - throw exception c#
¿Hay alguna razón para lanzar una DivideByZeroException? (16)
Aquí, un título ligeramente engañoso, no se trata de lanzar la (especial) DivideByZeroException, sino de la pregunta:
¿Debo usar excepciones al validar la entrada del usuario?
Esto probablemente se ha preguntado antes. Mi opinión: No, solo use un flujo que le permita manejar esto con códigos de error o valores booleanos.
Sin embargo, al validar ''datos'' en capas más profundas de una aplicación, lanzar una excepción suele ser lo correcto.
¿Hay casos en los que sea una buena idea throw
errores que puedan evitarse?
Estoy pensando específicamente en la DivideByZeroException
y ArgumentNullException
Por ejemplo:
double numerator = 10;
double denominator = getDenominator();
if( denominator == 0 ){
throw new DivideByZeroException("You can''t divide by Zero!");
}
¿Hay alguna razón para lanzar un error como este?
NOTA: No estoy hablando de detectar estos errores, sino específicamente de saber si hay alguna buena razón para lanzarlos.
SOLO PARA REITERAR
SÉ que en el ejemplo que di, probablemente será mejor que maneje el error. Tal vez la pregunta debería ser reformulada. ¿Hay alguna razón para throw
uno de estos errores en lugar de manejarlo en esta ubicación?
Considere que para los dobles, una división por cero resultará en un valor: double.Infinity, double.NegativeInfinity o double.NaN, dependiendo de si el numerador es positivo, negativo o cero, respectivamente.
Es posible que estos valores ya sean adecuados para su caso; de lo contrario, es probable que desee validar la entrada y actuar en consecuencia, antes de realizar la división.
Si está escribiendo una API (como en una biblioteca) y desea proporcionar un contrato que no permita una división por cero (digamos que expone el método que realiza algún tipo de división), entonces puede querer lanzar esta excepción. Sin embargo, por lo general, reservaría este tipo de excepción como indicador de un error programático.
El tiempo de ejecución de .NET ya es muy bueno para lanzar estas excepciones. También son altamente descriptivos de lo que está mal, no puede agregar ningún comentario bueno al mensaje de excepción. "No se puede dividir por cero" no agrega ningún valor.
Sin embargo, puede evitar muchas de estas excepciones seleccionando los valores que pasa el código del cliente. Querrá ArgumentNullException con el nombre de argumento si el código del cliente pasó un nulo, ArgumentException cuando pasó algo que puede hacer que DivideByZero se dispare.
En tu propio código, dudo que sea de mucha utilidad. Sin embargo, si está escribiendo una biblioteca que será consumida por otros, entonces debería usar excepciones como medio para comunicar los errores al código que consume su biblioteca.
"En el Marco, las excepciones se usan tanto para errores graves como para errores lógicos. Al principio, puede ser difícil adoptar el manejo de excepciones como el medio para reportar todas las fallas funcionales. Sin embargo, es importante diseñar todos los métodos públicos de un marco para reportar fallas en el método lanzando una excepción ".
Es una buena práctica realizar estas comprobaciones en la parte superior de la función antes de comenzar a procesar los datos. En lugar de lanzarlos (o cualquier otro método lanza estas excepciones) en medio de un método.
Hay absolutamente una razón para hacer esto, y como con la mayoría de las preguntas de lanzamiento, tiene que pensar en usted como un desarrollador que trabaja en equipo. Lo que está escribiendo puede ser parte de otro sistema, o puede ser una biblioteca o componente.
Si escribe una biblioteca de matemáticas y tiene una función llamada Divide(int a, int b)
que los divide, si alguien más quiere usar su método y pasa a cero, querrá lanzar una excepción para que, como un desarrollador, sabe que han jodido.
Si no lanza una excepción, introduce errores en su código. Si usé el método de división y puse los valores 10 y 0, lo que produce 10/0 y, por lo tanto, una excepción, la única respuesta correcta es el error. Si decide cambiar los valores para que no se produzca ningún error o devuelva 0, no es lo que estoy esperando. Supongo que mi división funcionó a la perfección y nunca noté un problema. Bien podría tomar ese 0 y apagarlo y usarlo en otros cálculos, sin saber que es la respuesta incorrecta, porque 10/0 no es 0.
Lanzar una excepción es una tarea costosa desde el punto de vista de los recursos. Ya ha impedido que se produzca una excepción, ¿por qué lanzar una? Si tiene que decirle al usuario, use algún mecanismo de mensajería. Si necesita saberlo usted mismo, inicie sesión.
Ninguna que se me ocurra. Yo solo programaría contra eso. Las excepciones pueden ser costosas, por lo que si puedes programar defensivamente contra ellas, hazlo en lugar de lanzar una excepción.
Al menos eso es lo que me dijo mi desarrollador senior cuando intenté capturar una DivideByZeroException hace muchas lunas.
Si está escribiendo una biblioteca BigInteger, entonces absolutamente debería lanzar una excepción DivideByZero
apropiada. Si estás escribiendo una biblioteca de carritos de compras, entonces ... eh, probablemente no.
No puedo, en este momento, pensar en una buena razón para lanzar una NullReferenceException
. Si está creando una API con documentación que dice "El primer parámetro para HummingBirdFeeder.OpenSugarWaterDispenser(Dispenser dispenser, int flowRate)
es el dispensador de agua con azúcar que desea abrir". Y si alguien aparece y pasa un valor nulo a este método, definitivamente debería lanzar una ArgumentNullException
.
Sin embargo, dejar una NullReferenceException
fuera de tu API solo sería pereza, porque eso es incorrecto y filtra algunos de tus aspectos internos.
EDITADO PARA AÑADIR:
Ahora que cambió la pregunta para referirse a una excepción ArgumentNullException
entonces la respuesta es fácil: sí, definitivamente debería lanzar ese tipo de excepción en estas circunstancias:
- Estás escribiendo un método público.
- Obtener un valor nulo para el argumento es de alguna manera inapropiado (es decir, el método no tiene sentido sin ese argumento en particular).
- La documentación del método indica que no se permiten valores nulos.
En ese caso, lo primero que debe hacer su método es verificar un valor nulo y lanzar una excepción si se viola la condición.
Si está escribiendo un método privado o interno, en la mayoría de los casos no necesitará validar los parámetros en tiempo de ejecución en la versión de lanzamiento. Puede asegurarse de que su propio código llame a su propio código correctamente. Una cosa que ayuda a crear esa garantía es validar los parámetros en la compilación de depuración agregando aserciones:
Debug.Assert(dispenser != null);
De esta manera, puede verificar que el código está actuando correctamente y detectar cualquier error antes sin ralentizar el código publicado con un montón de comprobaciones inútiles y redundantes.
Si está hablando de un código que interactúa directamente con la interfaz de usuario, entonces no. No puedo pensar en ninguna razón por la que quisieras.
Sin embargo, si está construyendo una clase / objeto utilizado por otros devlopers y han pasado datos que son claramente estúpidos, arroje el error apropiado durante su validación.
Si estaba escribiendo una clase numérica de alguna forma y puede haber esperado que el código que llama a su clase haya realizado la validación, puedo ver que puede ser útil lanzar la excepción DivisionByZeroException, pero en casi cualquier otro caso sería mejor verificar antes de la operación y lanzar y la excepción ArgumentException o ArgumentOutOfRange según corresponda.
NullReferenceException es una de las excepciones reservadas que el marco utiliza y que nunca debería lanzar a través de una API pública, junto con IndexOutOfRange, AccessViolationException y OutOfMemoryException. Consulte el libro de pautas de diseño del marco o la explicación de advertencia del análisis de código
Solo debe usar una excepción para manejar casos excepcionales.
En este caso, parece que un cero sería una entrada de usuario no válida. Debe verificar las entradas de usuario no válidas y manejarlas en consecuencia ANTES de llegar al punto en que una excepción sea adecuada.
Siempre que maneje la entrada correctamente, no debe haber ninguna razón para que ocurra una DivideByZeroException
. Si recibe una DivideByZeroException
incluso después de validar la entrada ... entonces sabe que tiene un problema real (en cuyo caso, la excepción es apropiada).
Supongamos que escribe una biblioteca para trabajar con enteros realmente grandes que no encajan en Int64, entonces es posible que desee lanzar la excepción DivideByZeroException para el algoritmo de división que escribe.
Si está confiando en un marco para hacer el trabajo (.NET o de otra manera), entonces debe dejar que el marco lance la excepción .
Esto facilitará que los consumidores de sus métodos manejen las excepciones que se lanzan de una manera estándar.
En el caso de dividir por cero, simplemente está reimplementando la misma lógica para lanzar una excepción como en el marco.
En teoría (y la práctica también), identificar y evitar / eliminar casos erróneos es mejor que tratarlos como excepciones. Sin embargo, no siempre es posible probar cada caso o ruta a través de su código, tampoco es posible en todos los casos controlar sus entradas.
Un principio de buen diseño es hacer que su programa reconozca y maneje con gracia situaciones excepcionales. Además, es una buena idea proporcionar a sus usuarios (y finalmente a usted mismo) información suficiente para diagnosticar los errores, especialmente aquellos que pueden ocurrir después de que se implemente su código. Por lo tanto, a veces tiene sentido lanzar excepciones como la que ilustra si hará que el código de su aplicación sea más robusto y más fácil de diagnosticar.
Nunca (el usuario nunca enviará 0 como denominador) y siempre (el usuario siempre proporcionará valores de argumentos apropiados) son ideas peligrosas para incluir en su código. Un porcentaje muy pequeño de nosotros solo programa, en código que nunca será modificado o llamado por otro desarrollador. Por lo tanto, tenemos que escribir código defensivo. En el caso de la división por cero, no debería decidir cuál debe ser el resultado apropiado, que recae en la persona que llama. Lanzar la excepción parece ser una forma razonable de devolver el problema. Si bien hay gastos involucrados, cualquier infraestructura que agregue a mi código para evitar lanzar la excepción también agrega gastos.