expected .net exception assertions

.net - expected - Debug.Assert vs Exceptions



mstest assert exception (8)

A menudo ambos: afirmar, luego lanzar.

Usted afirma porque desea notificar a los desarrolladores sobre una suposición errónea durante el desarrollo.

Lanzas porque si esto sucede en una compilación de lanzamiento, debes asegurarte de que el sistema no continúe procesando mientras está en mal estado.

Las características de confiabilidad deseadas de su sistema pueden afectar su elección aquí, pero "afirmar y arrojar" suele ser una estrategia útil, creo.

Sorprendentemente, solo pude encontrar una pregunta anterior sobre SO sobre este tema, y ​​me gustaría obtener la comunidad "Voto de confianza" (¡o no!) En mi enfoque.

La forma en que lo veo es así:

  • use Debug.Assert para indicar las cosas que espera que sean verdaderas. Esto se usaría cuando tengamos un control total sobre nuestro entorno, por ejemplo, en un método para verificar algunas condiciones previas y posteriores.
  • use Excepciones cuando surjan circunstancias excepcionales. Tratar con recursos externos, es decir, archivos, bases de datos, redes, etc. es pan comido. Pero...

Se pone un poco turbio en el siguiente escenario. Tenga en cuenta que este es un EJEMPLO CONTRARIO solo para ilustración.

Digamos que tenemos la clase MyClass, que tiene una propiedad pública MyMode y un método GetSomeValueForCurrentMode() . Considere MyClass como uno destinado a ser enviado (lanzamiento incorporado) en una biblioteca para uso de otros desarrolladores.

Esperamos que MyMode sea actualizado por usuarios externos de esta clase. Ahora, GetSomeValueForCurrentMode() tiene la siguiente lógica:

switch(MyMode) { case Mode.ModeA: return val1; case Mode.ModeB: return val2; default: //Uh-uh this should never happen }

Lo que quiero decir aquí es que el usuario de MyClass lo dejó en un estado inválido. ¿Entonces, qué debemos hacer?

En el valor predeterminado, ¿debemos throw new InvalidOperationException . throw new InvalidOperationException o throw new InvalidOperationException (u otra)?

Hay un mantra que dice que no debemos confiar en los usuarios de nuestras clases. Si seleccionamos Debug.Assert y construimos MyClass como una versión de lanzamiento (eliminando así las Aserciones de depuración), el usuario de la clase no obtendría información útil de que la había dejado en un estado no válido. Pero es un poco contrario al otro mantra que dice que solo arroja excepciones cuando suceden cosas completamente fuera de tu control.

Me parece dar vueltas en círculos con esto, uno de esos debates de programación que no parecen tener una respuesta "correcta" definitiva. ¡Así que pongámoslo a votación!

Editar: noté esta respuesta en una pregunta de SO relacionada (¿ diseño por contrato usando aserciones o excepciones? ):

La regla de oro es que debe usar las aserciones cuando intenta detectar sus propios errores y las excepciones cuando intenta detectar los errores de otras personas. En otras palabras, debe usar excepciones para verificar las condiciones previas para las funciones API públicas, y cada vez que obtenga datos que sean externos a su sistema. Debe usar afirmaciones para las funciones o datos que son internos a su sistema.

Para mí, esto tiene sentido, y se puede combinar con la técnica ''Assert then throw'' que se describe a continuación.

¡Pensamientos bienvenidos!


Básicamente estoy de acuerdo con la conclusión de tu propia pregunta: si el código de un piojo detecta un error cometido por un piojo, es un caso de A ssert (y las afirmaciones deben dejarse en el código de producción, a menos que el rendimiento dicte lo contrario). Si el código de Alice detecta un error en el código de E ve, es un caso de E xcepciones, suponiendo que Alice y Eve están en lados opuestos de su software de seguimiento de errores .

Ahora que es una regla general. Las afirmaciones, en una forma ligeramente modificada, también se pueden usar como un "desarrollador de heads-up". mecanismo (y luego no deberían llamarse "ASSERT" sino "HEADS_UP" o algo similar). ¿Qué sucede si su empresa desarrolla un producto cliente / servidor y el servidor envía datos no válidos al cliente? Si usted es un programador cliente, tiene ganas de tratarlo como datos externos (son los datos de Eve los que están kaputt) y desea lanzar una excepción. Pero una afirmación "más suave", que hace que el depurador de Visual Studio se detenga allí mismo, puede ser una muy buena forma de detectar esos problemas muy temprano e informarlo al equipo del servidor. En una instalación real, podría ser que Mallory atempere con los datos entre Eve y Alice, pero la mayoría de las veces es un error de uno de tus colegas, y quieres verlo cuando sucede, es por eso que los llamo Afirmaciones "heads-up": no reemplazan las excepciones, pero te dan una advertencia y una oportunidad de inspeccionar el problema.


Depende del idioma, es afirmar si sintaxis de azúcar, entonces deberías usarlo. sin embargo, en Java afirma que debe activarse para que funcione, por lo que la excepción es mejor. Sin embargo, siempre es mejor tener una excepción específica, por lo que aquí debería ser IllegalStateException.


En .Net, los métodos de clase Debug no están incluidos en su programa cuando realiza una compilación de lanzamiento, por lo que deberá lanzar una excepción si este código llega a producción.


Estoy de acuerdo con la mayoría de la gente aquí y sigo Design-by-Contract. Debería intentar y diferenciar muy claramente entre los requisitos en el código desplegado (Contratos) y descifrar el estado esperado durante el diseño (Afirmaciones de depuración).

SIEMPRE debe arrojar afirmaciones de contrato como excepciones (ya que siempre deben ser excepcionales). Hay mecanismos integrados en la mayoría de los marcos para capturar aserciones de depuración. Pero en el tiempo de ejecución siempre deberías lanzar una excepción.

Utilizo una biblioteca personalizada para ayudar con esto (en C # / VB.NET). Recientemente lo presenté en Codeplex ( http://www.contractdriven.com/ ) si le interesa cómo funciona esto en la práctica.

Un beneficio adicional de esto es que a medida que comienza a utilizar DbC más regularmente, rara vez necesita usar las aserciones de depuración ya que existen garantías explícitas escritas en su código, por lo que es realmente difícil entrar en un estado no válido.

Entonces la pregunta en su publicación original ... "Lo que estoy obteniendo aquí es que el usuario de MyClass lo dejó en un estado inválido. Entonces, ¿qué deberíamos hacer?" ... nunca debería surgir.

¡Es posible que nunca tengas que volver a depurar nada! ;-)


Mi uso de afirmaciones sigue las ideas del diseño por contrato . Básicamente, afirma que los parámetros entrantes, variables globales y otra información de estado son válidos a medida que ingresa su función, y afirma que los valores de retorno y el estado también son válidos a medida que se va. Si obtiene una afirmación fallida al inicio, es un error en el código de llamada, si la obtiene al final, el error está en este código. Estas son condiciones previas y condiciones posteriores.

Una afirmación en su declaración de cambio solo es realmente útil si ha verificado sus condiciones previas al ingresar. Si llega a un estado inaceptable en el medio de su función en este escenario, es un error en su función o función llamada. Personalmente, me quedaría con una afirmación aquí ya que no es una excepción. Como implica, las excepciones se relacionan con los recursos, no con los errores. Sin embargo, puede crear un controlador de aserciones personalizado que exista en la compilación de lanzamiento y lanzar una excepción en caso de error, para darle a su programa la oportunidad de volver a un estado estable.


Yo diría: use una excepción si el error está en el código de otra persona o en un subsistema diferente (ya sea que lo haya escrito o no). También use una excepción si hay un error en los datos que provienen de una fuente externa, como un archivo.

A veces, no sabe si los datos provienen de una fuente externa o no. Si la seguridad es importante y existe la posibilidad de que esté tratando con datos externos que no se han verificado como correctos, use una excepción. Si la seguridad no es importante, entonces usaría el rendimiento como un desempate: ¿se podría ejecutar este código en un ciclo cerrado? De ser así, considere usar una afirmación, ya que obtendrá un mejor rendimiento en una compilación de versión. De lo contrario, use una excepción.


Primero, MyClass siendo válido debería, por supuesto, ser expresado por el invariante de MyClass.

En segundo lugar, dices "Esperamos que MyMode sea actualizado por usuarios externos de esta clase"; por supuesto, el colocador de este modo debe tener el típico diseño por contrato (como cualquier función pública):

void Setter(mode m) { // INVARIANT ASSERT (1) // PRECONDITION ASSERTS (uses "m") (2) // BODY (3) // POSTCONDITION ASSERTS (if any) (4) // INVARIANT ASSERT (5) }

En (5) fallarías con una violación de aseveración gritadora que el invariante no contiene. Pero en (2) fallarías antes, porque el modo m pasado no es válido. Esto enviaría un mensaje claro al usuario y así resolvería su problema.

Y por favor no me diga que el campo de modo es público y los usuarios lo cambian sin ningún tipo de control.

Editar: Acerca de las afirmaciones y el modo de lanzamiento, ver también: