20

¿Hay algún caso en que sea una buena idea detectar throw errores que pueden evitarse?¿Hay alguna razón para lanzar una DivideByZeroException?

Estoy pensando específicamente de 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 razones para lanzar un error como este?

NOTA: No estoy hablando de captura estos errores, pero específicamente en saber si hay alguna buenas razones para tirarlos.

Sólo para reiterar:

Yo sé que en el ejemplo que di lo que probablemente sea mejor manejo del error. Quizás la pregunta deba reformularse. ¿Hay alguna razón para throw uno de estos errores en lugar de manejarlo en esta ubicación.

+0

Los contratos de código pueden aliviar este problema. –

+0

Nota: Las respuestas de Juhar y nobugz son muy buenas. – Armstrongest

Respuesta

19

Digamos que usted escribe una biblioteca para trabajar con enteros realmente grandes que no se ajustan a Int64, entonces es posible que desee lanzar DivideByZeroException para el algoritmo de división que escriba.

+0

Buena respuesta, y sacas un buen punto de ventaja. – Beska

+0

¿Sería capaz de elaborar sobre este. Suena como un caso de borde interesante. – Armstrongest

+6

@Atomiton - De hecho, he hecho exactamente esto antes. Si ha escrito una biblioteca matemática, y el código de llamada le da un denominador cero, ¿qué más podría hacer sino lanzar la excepción? La biblioteca de matemáticas no sabe lo que estás tratando de hacer. No hay una forma correcta de manejar la situación en ese lugar. Solo el código de llamada tiene suficiente visión general para saber qué hacer al respecto.Entonces lanza la excepción. –

0

Nada que se me ocurra. Yo solo programaría en contra de eso. Las excepciones pueden ser costosas, por lo tanto, si puede realizar un programa defensivo en su contra, hágalo en lugar de lanzar una excepción.

Al menos eso es lo que mi desarrollador senior me dijo cuando intenté capturar una DivideByZeroException hace muchas lunas.

+2

Debería programarse defensivamente en su contra, pero eso no significa que deba suponer necesariamente que nunca sucederá y no atraparlo. Podrías ser increíble y manejar cada caso de UI ... pero luego, más tarde, alguien agrega algunas características nuevas a la interfaz de usuario y no son tan inteligentes ... boom. Si puede atrapar con gracia la excepción, hacer las notificaciones necesarias y el registro, y luego continuar, puede ser una buena idea. – Beska

+0

buen punto. pero si siempre haces esto: if (denominator == 0) {} entonces no tendrás el problema. Pero veo tu punto. –

+0

@Beska - No, nunca debe continuar un programa en un estado no válido o desconocido. Cuando se producen errores inesperados, la notificación adecuada se debe emitir y registrar, y luego el programa debe morir de muerte repentina. Manejar los errores "con gracia" es una ruta corta al código de errores y al infierno del mantenimiento. –

-1

Lanzar una excepción es una tarea costosa desde el punto de vista de un recurso. Ya has evitado que se produzca una excepción, ¿por qué lanzar uno? Si tiene que decirle al usuario, use algún mecanismo de mensajería. Si necesita saberlo usted mismo, conéctelo.

+0

Exactamente. Estoy de acuerdo contigo. Entonces, ¿hay CUALQUIER caso en que uno "arroje" una "DivideByZeroException"? No puedo pensar en ninguna. Es por eso que hice la pregunta en SO. – Armstrongest

+2

Si no va a lanzar la excepción, ¿qué valor va a devolver su método de división en ese escenario? – cdkMoose

+0

No hay nada de malo en lanzar excepciones. Si le preocupa que algún método pueda arrojar una excepción, debe verificar las entradas antes de llamar al método o ajustar la llamada en un bloque try/catch. Esto debería estar en la persona que usa el método, no en la persona que escribe el método. –

4

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. Usted debe verificar la entrada del usuario no válido y manejarlo en consecuencia ANTES se llega a tal punto que una excepción sería approriate.

Mientras usted maneja correctamente la entrada, no debería haber ninguna razón para que un DivideByZeroException suceda. Si recibe un DivideByZeroException incluso después de validar la entrada ... entonces sabrá que tiene un problema real (en cuyo caso, la excepción es apropiada).

+2

Estoy de acuerdo con su punto general, aunque creo que el viejo adagio de que las excepciones son solo para "casos excepcionales" es demasiado explícito. Krzysztof Cwalina ciertamente lo cree así - http://blogs.msdn.com/kcwalina/archive/2008/07/17/ExceptionalError.aspx –

+0

@Dan En mi opinión, Krzysztof simplemente está replanteando la definición de lo que considero una Excepción caso (un caso en el que se produce un error real, no algo que podría capturarse fácilmente con validación de entrada, etc.). –

+0

Pero si estás escribiendo una biblioteca consumida por otros ...? Creo que de eso se trata. El escritor de la biblioteca no puede determinar de antemano qué será excepcional y cuál será el lugar común cuando se trata de cómo alguien consume su API. –

0

Es una buena práctica para hacer estos controles en la parte superior de la función antes de empezar el procesamiento de datos. En lugar de tirarlos (o cualquier otro método arroja estas excepciones) en medio de un método.

+1

Estoy de acuerdo. Sin embargo, eso no es lo que estaba preguntando. :-) – Armstrongest

3

Si estamos hablando sobre el código que está interactuando directamente con la interfaz de usuario, entonces no. No puedo pensar en ninguna razón por la que te gustaría.

Sin embargo, si usted está construyendo una clase/objeto utilizado por otros devlopers y que ha pasado en los datos que es claramente estúpida luego tirar el error apropiado durante su validación.

11

El tiempo de ejecución de .NET ya es muy bueno para lanzar estas excepciones. También son muy descriptivos de lo que está mal, no se puede agregar ningún buen comentario al mensaje de excepción. "No se puede dividir por cero" no agrega ningún valor.

Sin embargo, puede evitar muchas de estas excepciones mediante el cribado de los valores que pasa el código de cliente. Querrá ArgumentNullException con el nombre del argumento si el código del cliente pasó un nulo, ArgumentException cuando pasó algo que puede provocar el corte de DivideByZero.

+0

Suprimí mi respuesta y te voté ... dijiste más claramente que yo. Prestigio. – Beska

+0

Definitivamente esto. Incluso si está escribiendo una biblioteca matemática, no debe lanzar DivideByZeroExceptions. Por la misma razón, nunca deberías lanzar una NullReferenceException, básicamente: este tipo de excepciones dice 'la biblioteca tiene errores'. Lo que * quieres * decir es 'estás usando la biblioteca mal'. ArgumentExceptions es perfecto. – Joren

+1

Si desea enviar excepciones al usuario y usar el mensaje de excepción para mostrar al usuario dónde salió mal, puede ser una buena idea proporcionar un mensaje personalizado. por ejemplo, 'LiteralErrorMsg1.Text = ex.Message' Otro escenario sería la localización. Es posible que también desee mostrar el mensaje de error en el idioma del usuario. – Armstrongest

0

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 un buen diseño es tener su programa de reconocer y manejar con gracia situaciones excepcionales. Además, es una buena idea proporcionar a sus usuarios (y en última instancia a usted) la información suficiente para diagnosticar errores, especialmente aquellos que pueden ocurrir después de que se implemente su código. Por lo tanto, tiene a veces tiene sentido arrojar excepciones como el tipo que ilustra si hará que su código de aplicación sea más robusto y fácil de diagnosticar.

+0

¿Puedes elaborar un poco o dar un ejemplo? Estoy particularmente interesado en su segundo punto ... que a veces es una buena idea arrojar errores esperados como este (que de otro modo podrían manejarse) – Armstrongest

+0

@Atomiton - Lo veo como una práctica de codificación defensiva. Nunca puede estar 100% seguro de que realmente cubrió todas las rutas e impidió que se pasaran todos los datos erróneos a un cuerpo de código en particular. Como tal, vale la pena tener una lógica que detecte eleva tales condiciones (cuando puede) para que en la producción pueda proporcionar detalles suficientes para ayudar a diagnosticar rápidamente dichos problemas si ocurren. La premisa básica es: probar que una entrada particular nunca pasará a un método es * difícil * - es mucho más fácil verificar las entradas para la validez dentro del método. http://en.wikipedia.org/wiki/Defensive_programming – LBushkin

5

No hay absolutamente una razón para ello, y como con la mayoría de las preguntas que lanzan una excepción, hay que pensar en ti como un desarrollador que trabaja en un 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 los pasa en cero, querrá lanzar una excepción para que ellos, como desarrollador, sepan ellos han jodido.

Si no lanza una excepción, se introducen errores en el código. Si utilicé su método de división, y pongo los valores 10 y 0, que producen 10/0 y, por lo tanto, una excepción, la única respuesta correcta es el error. Si decide cambiar los valores para que no ocurra ningún error, o si devuelve 0, eso no es lo que estoy esperando, supongo que mi división funcionó a la perfección, y nunca noté ningún problema. Bien podría tomar ese 0 e irme y usarlo en otros cálculos, sin saber que es la respuesta incorrecta, porque 10/0 no es 0.

+0

10D/0D = double.Infinity, no es un error. Dependiendo de la naturaleza de la aplicación, esto podría representarse como el símbolo de infinito (∞) o representarse como un error. –

+0

¡Ah! ¡Gran respuesta! Entonces ... ¡arrojaría el error en casos en los que quisiera subir la Excepción a un nivel superior en lugar de manejarlo! – Armstrongest

+0

¿Pero cuál es el punto de verificar y lanzar manualmente la excepción, cuando podría simplemente ejecutar la división y arrojaría la excepción para usted? –

1

En su propio código, dudo que haya mucho uso. Sin embargo, si está escribiendo una biblioteca que será consumida por otros, entonces debe usar excepciones como medio para comunicar los errores al código que consume su biblioteca.

"En el marco, las excepciones se utilizan tanto para los errores de hardware y lógicas errores. Al principio, puede ser difícil para abrazar el manejo de excepciones como las medios de notificación todos fallos funcionales. Sin embargo, es importante diseño de todos los métodos públicos de un marco reportar el método-fracasos por lanzar una excepción ".

Krzysztof Cwalina, Designing Reusable Frameworks

2

Si estás escribiendo una biblioteca BigInteger, a continuación, a pesar de todo debe lanzar una excepción adecuada DivideByZero. Si estás escribiendo una biblioteca de carrito de la compra, entonces ... eh, probablemente no.

No puedo, por el momento, pensar en una buena razón para lanzar un NullReferenceException. Si está creando una API con documentación que diga "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 viene y le da un valor nulo a este método, entonces definitivamente deberías lanzar un ArgumentNullException.

Permitir que NullReferenceException fuera de su API simplemente sería pereza, porque eso está mal y se filtra parte de su funcionamiento interno.

editar para agregar:

Ahora que ha cambiado la pregunta para referirse a una ArgumentNullException entonces la respuesta es fácil: sí, definitivamente debe tirar ese tipo de excepción en estas circunstancias:

  • Usted están escribiendo un método público.
  • Obtención de 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 los valores nulos no están permitidos.

En ese caso, lo primero que debe hacer su método es buscar un valor nulo y lanzar una excepción si se infringe la condición.

Si está escribiendo un método privado o interno, en la mayoría de los casos no tendrá que validar los parámetros en tiempo de ejecución en la compilación de lanzamiento. Puede asegurarse de que su propio código llame correctamente a su propio código. Una cosa que ayuda a crear esa seguridad es validar los parámetros de la versión de depuración por assersions agregó:

Debug.Assert(dispenser != null); 

esta manera se puede verificar que el código está actuando correctamente y detectar cualquier error anterior sin ralentizar el código publicado con un montón de cheques inútiles y redundantes.

+0

Gracias! En realidad, escribí NullReferenceException ... pero estaba pensando en ArgumentNullException. ¡Gracias! ¡Voy a corregir la pregunta! – Armstrongest

1

título un poco engañoso aquí, no se trata de tirar la DivideByZeroException (especial), sino más bien la pregunta:

¿Debo usar excepciones al validar la entrada del usuario?

Esto probablemente se haya preguntado antes. Mi opinión: No, solo use un flujo que le permita manejar esto con códigos de error o booleanos.

Sin embargo, al validar 'datos' en capas más profundas de una aplicación, lanzar una excepción suele ser lo correcto.

+0

Gracias por el comentario. Pero, quería saber si había casos para arrojar un error que es tan obviamente fácil de verificar, así que específicamente lo mencioné. El concepto de capas más profundas (respondido por algunas personas ya) es una especie de lo que estaba buscando. – Armstrongest

0

Considere que para los dobles, una división por cero realmente dará como resultado 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, probablemente quiera 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 (supongamos que expone el método que realiza algún tipo de división), entonces puede arrojar esta excepción .Sin embargo, normalmente, reservaría este tipo de excepción como indicador de un error programático.

1

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, entonces puedo ver que puede ser útil lanzar DivisionByZeroException pero en casi cualquier otro caso sería mejor verificar antes la operación y throw y la excepción ArgumentException o ArgumentOutOfRange según corresponda.

NullReferenceException es una de las excepciones reservadas que utiliza el marco que nunca debe arrojar a través de una API pública, junto con IndexOutOfRange, AccessViolationException y OutOfMemoryException. Ver el libro directrices de diseño de marco o del Code Analysis warning explanation

+0

Gracias. Corregí la pregunta (+1 por alertarme). Quise decir 'ArgumentNullException' – Armstrongest

+0

Si está implementando su propio indizador, lista, diccionario, tabla hash, ¿cuál sería el error al lanzar' IndexOutOfRange' –

+0

Buen punto Matt – Armstrongest

0

Nunca (el usuario no enviará 0 como denominador) y siempre (el usuario siempre proporcionará valores de los argumentos apropiados) son ideas peligrosas para incluir en su código. Un porcentaje muy pequeño de nosotros programa solo, en código que nunca será modificado o llamado por otro desarrollador. Entonces, necesitamos escribir un código defensivo. En el caso de la división por cero, no debería decidir cuál debería ser el resultado apropiado, que recae sobre la persona que llama. Lanzar la excepción parece 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.

0

Si confía en un marco para hacer el trabajo (.NET o de otro modo), entonces debe dejar que el marco arroje la excepción.

Esto facilitará que los usuarios de sus métodos manejen las excepciones que se lanzan de manera estándar.

En el caso de dividir por cero, simplemente está implementando de nuevo la misma lógica para lanzar una excepción que en el marco.

Cuestiones relacionadas