He leído muchos artículos (y un par de otras preguntas similares que se publicaron en StackOverflow) sobre cómo y cuándo usar afirmaciones, y las entendí bien. Pero aún así, no entiendo qué tipo de motivación debería llevarme a usar en Debug.Assert
lugar de lanzar una simple excepción. Lo que quiero decir es que en .NET la respuesta predeterminada a una afirmación fallida es "detener el mundo" y mostrar un cuadro de mensaje al usuario. Aunque este tipo de comportamiento podría modificarse, me resulta muy molesto y redundante hacer eso, mientras que podría, en cambio, lanzar una excepción adecuada. De esta manera, podría escribir fácilmente el error en el registro de la aplicación justo antes de lanzar la excepción y, además, mi aplicación no necesariamente se congela.
Entonces, ¿por qué debería usar, en todo caso, en Debug.Assert
lugar de una simple excepción? Colocar una aserción donde no debería estar podría causar todo tipo de "comportamiento no deseado", así que desde mi punto de vista, realmente no gano nada usando una aserción en lugar de lanzar una excepción. ¿Estás de acuerdo conmigo o me falta algo aquí?
Nota: Entiendo completamente cuál es la diferencia "en teoría" (Depurar vs Liberar, patrones de uso, etc.), pero como yo lo veo, sería mejor lanzar una excepción en lugar de realizar una afirmación. Dado que si se descubre un error en una versión de producción, todavía querría que la "aserción" fallara (después de todo, la "sobrecarga" es ridículamente pequeña), así que será mejor lanzar una excepción en su lugar.
Editar: A mi modo de ver, si una afirmación falló, eso significa que la aplicación entró en algún tipo de estado dañado e inesperado. Entonces, ¿por qué querría continuar con la ejecución? No importa si la aplicación se ejecuta en una versión de depuración o de lanzamiento. Lo mismo vale para ambos
fuente
Respuestas:
Aunque estoy de acuerdo en que su razonamiento es plausible , es decir, si una afirmación se viola inesperadamente, tiene sentido detener la ejecución arrojándola, personalmente no usaría excepciones en lugar de afirmaciones. Este es el por qué:
Como han dicho otros, las aseveraciones deben documentar situaciones que son imposibles , de tal manera que si se da la situación supuestamente imposible, se informe al desarrollador. Las excepciones, por el contrario, proporcionan un mecanismo de flujo de control para situaciones excepcionales, poco probables o erróneas, pero no para situaciones imposibles. Para mí, la diferencia clave es esta:
SIEMPRE debería ser posible producir un caso de prueba que ejercite una declaración de lanzamiento determinada. Si no es posible producir un caso de prueba de este tipo, entonces tiene una ruta de código en su programa que nunca se ejecuta, y debe eliminarse como código muerto.
NUNCA debería ser posible producir un caso de prueba que provoque una afirmación. Si se activa una afirmación, el código es incorrecto o la afirmación es incorrecta; de cualquier manera, algo debe cambiar en el código.
Es por eso que no reemplazaría una afirmación con una excepción. Si la aserción no se puede disparar, reemplazarla con una excepción significa que tiene una ruta de código no comprobable en su programa . No me gustan las rutas de código no comprobables.
fuente
Las afirmaciones se utilizan para comprobar la comprensión del mundo por parte del programador. Una afirmación debe fallar solo si el programador ha hecho algo mal. Por ejemplo, nunca use una aserción para verificar la entrada del usuario.
Afirma la prueba de condiciones que "no pueden suceder". Las excepciones son para las condiciones que "no deberían ocurrir pero sí".
Las afirmaciones son útiles porque en el momento de la compilación (o incluso el tiempo de ejecución) puede cambiar su comportamiento. Por ejemplo, a menudo en las versiones de lanzamiento, las afirmaciones ni siquiera se controlan, porque introducen una sobrecarga innecesaria. Esto también es algo de lo que debe tener cuidado: es posible que sus pruebas ni siquiera se ejecuten.
Si usa excepciones en lugar de afirmaciones, pierde algo de valor:
El código es más detallado, ya que probar y lanzar una excepción tiene al menos dos líneas, mientras que una aserción es solo una.
Su código de prueba y lanzamiento siempre se ejecutará, mientras que las afirmaciones se pueden compilar.
Pierde algo de comunicación con otros desarrolladores, porque las afirmaciones tienen un significado diferente al código de producto que verifica y arroja. Si realmente está probando una aserción de programación, use una aserción.
Más aquí: http://nedbatchelder.com/text/assert.html
fuente
EDITAR: En respuesta a la edición / nota que hizo en su publicación: parece que usar excepciones es lo correcto en lugar de usar afirmaciones para el tipo de cosas que está tratando de lograr. Creo que el obstáculo mental que está encontrando es que está considerando excepciones y afirmaciones para cumplir el mismo propósito, por lo que está tratando de averiguar cuál sería "correcto" para usar. Si bien puede haber cierta superposición en la forma en que se pueden usar las afirmaciones y excepciones, no confunda que para ellas son soluciones diferentes para el mismo problema, no lo son. Las afirmaciones y las excepciones tienen cada una su propio propósito, fortalezas y debilidades.
Iba a escribir una respuesta con mis propias palabras, pero esto hace que el concepto sea más justo de lo que yo hubiera hecho:
Estación C #: afirmaciones
Básicamente, use excepciones para cosas que necesitan ser detectadas / tratadas en una aplicación de producción, use aserciones para realizar verificaciones lógicas que serán útiles para el desarrollo pero que se desactivan en producción.
fuente
Creo que un ejemplo práctico (artificial) puede ayudar a aclarar la diferencia:
(adaptado de la extensión Batch de MoreLinq )
Entonces, como han dicho Eric Lippert et al, solo afirma cosas que espera que sean correctas, en caso de que usted (el desarrollador) lo haya usado accidentalmente en otro lugar, para que pueda corregir su código. Básicamente, lanza excepciones cuando no tiene control o no puede anticipar lo que ingresa, por ejemplo , para la entrada del usuario , de modo que lo que le dio datos incorrectos puede responder de manera apropiada (por ejemplo, el usuario).
fuente
Otra pepita de Code Complete :
Continúa agregando algunas pautas sobre lo que debe y no debe afirmarse.
Por otro lado, excepciones:
Si no tiene este libro, debería comprarlo.
fuente
Debug.Assert de forma predeterminada solo funcionará en compilaciones de depuración, por lo que si desea detectar cualquier tipo de comportamiento inesperado en sus compilaciones de lanzamiento, deberá usar excepciones o activar la constante de depuración en las propiedades de su proyecto (que se considera en general para no ser una buena idea).
fuente
Use afirmaciones para cosas que SON posibles pero que no deberían suceder (si fuera imposible, ¿por qué pondría una afirmación?).
¿No suena como un caso para usar un
Exception
? ¿Por qué usarías una aserción en lugar de unaException
?Porque debería haber un código que se llame antes de su aserción que evitaría que el parámetro de la aserción sea falso.
Por lo general, no hay ningún código antes de su
Exception
que garantice que no se lanzará.¿Por qué es bueno que
Debug.Assert()
se compile en prod? Si quiere saberlo en debug, ¿no querría saberlo en prod?Lo desea solo durante el desarrollo, porque una vez que encuentra
Debug.Assert(false)
situaciones, escribe código para garantizar que esoDebug.Assert(false)
no vuelva a suceder. Una vez finalizado el desarrollo, asumiendo que ha encontrado lasDebug.Assert(false)
situaciones y las ha solucionado,Debug.Assert()
se pueden compilar de forma segura, ya que ahora son redundantes.fuente
Suponga que es miembro de un equipo bastante grande y hay varias personas trabajando en la misma base de código general, incluida la superposición de clases. Puede crear un método que sea llamado por varios otros métodos, y para evitar la contención de bloqueo, no le agrega un bloqueo separado, sino que "asume" que fue bloqueado previamente por el método de llamada con un bloqueo específico. Por ejemplo, Debug.Assert (RepositoryLock.IsReadLockHeld || RepositoryLock.IsWriteLockHeld); Los otros desarrolladores pueden pasar por alto un comentario que dice que el método de llamada debe usar el bloqueo, pero no pueden ignorarlo.
fuente