try practices net handling error custom catch best asp .net exception error-handling

.net - practices - throw exception c#



¿Es una mala práctica devolver las excepciones de tus métodos? (16)

Muchos de los métodos de base de código que mis compañeros han escrito realizan su propio manejo de errores, generalmente capturando, notificando y registrando.

En estos casos, los métodos devuelven un valor booleano, indicando éxito o error.

Sin embargo, a veces, si un método falla, quiero que el código de llamada sepa por qué, y devolver un booleano no es suficiente.

Una forma de evitar esto es mantener el manejo de errores en los métodos, pero haga que el método sea nulo y haga que los métodos arrojen sus Excepciones.

Sin embargo, recientemente adquirí el hábito de devolver Excepciones en métodos apropiados, generalmente métodos de acción que de otro modo podrían ser nulos, pero donde me gustaría saber el estado de la acción.

Las ventajas de devolver una excepción sobre tener un método nulo arrojan una excepción es que creo que facilita a otros programadores el uso de su biblioteca, y, lo que es más importante, significa que puede llamar a ese método sin tener que preocuparse de atrapar el Excepción

Por ejemplo, si el método es simplemente vacío, puede no ser instantáneamente obvio que el programador debe manejar el éxito o el fracaso.

Pero si los métodos especifican específicamente un tipo de excepción de devolución, entonces usted sabe que puede verificar el éxito o el fracaso si así lo desea. Pero también significa que no necesita preocuparse por detectar el error si no lo desea.

¿Tiene sentido? Quizás no he usado el mejor ejemplo, pero en general, ¿está bien devolver Excepciones, o hay un patrón mejor?

ACTUALIZAR

wow, el resultado abrumador es de ninguna manera . Ya me lo imaginaba. Debo decir que al hacerlo (devolviendo una excepción) se solucionó un problema, pero se sintió mal.

Entonces, a partir de algunas de sus respuestas, la mejor solución para estos escenarios específicos (una clase compleja, o una clase con una o más dependencias externas (es decir, servicio web)) parece ser una clase de resultados personalizada.

ACTUALIZAR:

Realmente aprecio todas las opiniones, estoy leyendo todo, y estoy pensando cuidadosamente sobre todos los comentarios.

Actualmente estoy a favor de tener un método nulo, lanzar las Excepciones y luego atraparlas por fuera ... ¿es eso mejor?


Definitivamente un uso poco ortodoxo de excepciones. La característica que hace que las excepciones sean poderosas es que una excepción que se lanza puede generar una gran cantidad de capas en la pila de llamadas. Si simplemente lo devuelve, pierde esa propiedad (pero también el impacto negativo en el rendimiento asociado con eso).

Realmente no veo cómo esto es diferente de simplemente devolver una instancia de una clase que contiene información sobre posibles errores. La única diferencia es que devolver objetos que heredan de la clase Exception puede causar cierta confusión en otros desarrolladores que leerán su código más adelante.

Entonces, si bien no hay nada de malo en devolver objetos con información sobre errores, sugiero usar clases que no hereden de Exception para ese fin, para evitar confusiones.


Devolver una excepción en el escenario que describió es una mala idea ya que las excepciones no están diseñadas para ese propósito.

Sería mejor crear su propia estructura o clase que contenga la información que necesita y devolverla en su lugar.

public enum MyErrorType { Abc, Xyz, Efg }; public struct Result { public bool Success; public MyErrorType ErrorType; };

y luego el método:

private Result MyMethod() { // code }


Las excepciones pueden ser agradables en algunos entornos, pero tenga en cuenta que pueden incurrir en un gran golpe de rendimiento.


Nadie más ha dicho esto: mi entendimiento es que en .NET, el seguimiento de la pila de una Excepción no se completa hasta que se lanza la Excepción. Ver las mejores prácticas para manejar excepciones donde dice:

  • El seguimiento de la pila comienza en la declaración donde se lanza la excepción y finaliza en la declaración catch que capta la excepción. Tenga en cuenta este hecho al decidir dónde colocar una declaración de lanzamiento.

  • Use métodos de creación de excepciones. Es común que una clase arroje la misma excepción desde diferentes lugares en su implementación. Para evitar un código excesivo, utilice los métodos auxiliares que crean la excepción y la devuelven.

En .NET, si simplemente crea una instancia de una excepción y la devuelve, no tendrá ninguna información de pila en esa excepción. Este es un beneficio cuando usa esta característica para hacer un método de creación de excepciones, una pérdida cuando usa Excepciones de la forma en que pregunta. En comparación, en Java, la información de la pila se agrega cuando se crea una instancia de la Excepción, independientemente de si alguna vez se lanza.

Por lo tanto, en .NET cuando devuelve una excepción que nunca se lanzó, usted renuncia al mismo seguimiento de pila que le indica dónde ocurrió el problema. Tal vez no te importa, en este caso, pero pensé que valía la pena señalarlo.

La sobrecarga de rendimiento de una Excepción lanzada es razonablemente pequeña en cualquier JVM moderna y en cualquier versión reciente de .NET. Devolver una excepción en lugar de arrojarla, por razones de rendimiento, es una optimización inapropiada ... a menos que hayas perfilado tu programa y hayas descubierto que un lanzamiento específico es realmente un cuello de botella, y que devolver la excepción hace una diferencia significativa. (Lo cual me sorprendería, pero todo es posible).

Nota: Supongamos que crea un método que de otro modo sería void devuelve una excepción en caso de error. Esto significa que si desea verificar si hay algún error, debe verificar con null para ver si hubo un error o no. Como regla general, los métodos que devuelven nulo en caso de error contribuyen al código frágil. Por ejemplo, un método que devuelve una Lista debería devolver una Lista vacía, en lugar de nula.

También tenga en cuenta que en .NET cuando vuelve a lanzar una excepción, porque la pila se completa en una cláusula throw , generalmente perderá el seguimiento original de la pila. Para evitar esto, use el throw sin especificar la instancia de excepción. Si throw ex , perderá la traza original de la pila.


No estoy seguro del daño al devolver una excepción, ya que lo hago para poder informar el mensaje de excepción, el tipo y la información relacionada en un registro de excepción en un servidor SQL.

Algunas ''excepciones'', como la conexión del servidor SQL, fallaron al informar otras excepciones. No es necesario que suba a otro nivel; Puedo intentar escribirlos en una unidad de red en lugar de colgarlos.

Otros tipos de excepciones Me gustaría comprobar si el método que llamó a la función puede manejar ese problema específico sin el golpe de rendimiento de lanzarlo realmente

Además de estos métodos, incluyo un parámetro booleano que permite al que llama decidir si debe lanzar la excepción o simplemente devolverla.


No, está bastardeando completamente el lenguaje (tecnología, ya que solo especificas .NET).

También estoy en desacuerdo con que haga que sus API sean más fáciles de usar para otros, cualquiera que haya aprendido y tenga una comprensión básica de la programación utilizando un modelo que incluya excepciones, le resultará más difícil usar su código.

¿Qué sucede si, en el futuro, su método necesita devolver un valor? ¿Qué pasa si hay más de un escenario de error? Si realmente desea saber más acerca de cómo fue el método, entonces necesita crear una clase que encapsule tanto el resultado como cualquier información de estado adicional que desee.


No, no lo consideraría una buena práctica.

Las excepciones son bien nombradas: deben ser circunstancias excepcionales, no la norma. Es imposible escribir una función de esta manera, porque no puede devolver los frutos del cálculo si está devolviendo una excepción.

No debe manejar excepciones en sus métodos a menos que realmente tenga una estrategia de recuperación que valga la pena implementar. No cuento el registro y el relanzamiento como una estrategia de recuperación.

Siempre puede evitar que sus clientes tengan que escribir bloques de prueba / captura lanzando excepciones sin marcar.


No.

Las excepciones deberían ser algo que existe solo en casos excepcionales (de ahí el nombre). La única vez que pude ver que un método devolviera una excepción sería algún tipo de método de fábrica cuyo objetivo fuera específicamente crear la excepción, pero incluso así, se trata de hacer más estrictas las cosas.

Si necesita devolver más información que un booleano, cree una clase personalizada (no derivada de una excepción) que incluya su booleano + otra información.


Nunca deberías devolver excepciones. En cambio, si su función es suficientemente compleja, cree una clase que sea el resultado de su función. Por ejemplo, el método GetPatientList devuelve GetPatientListResult. Podría tener un miembro de Success. Las excepciones son para cosas realmente poco comunes, como un archivo que desaparece a mitad de operación, parámetros inválidos o nulos que se establecen para una función, la base de datos baja. Además, rompe el modelo de abstracción completo: Dog.GoForAWalk debe devolver DogWalkReport, no PossiblyNullDogWalkException.


Nunca he visto un método que devuelva una excepción. En general, el método devuelve un valor y ese método puede arrojar una excepción. Pero nunca he visto código con return new System.InvalidOperationException ("Logfile no puede ser de solo lectura"); por ejemplo...

Entonces, para responder a su pregunta, diría que sí, es malo ...


Si le preocupa que otros programadores no los capturen, puede usar herramientas de análisis de código para asegurarse de que todas las excepciones estén atrapadas. Incluso puede ser posible escribir atributos personalizados para lograr algo así como excepciones comprobadas en Java.

Habiendo dicho eso, ¿no es más fácil seguir convenciones bien establecidas y solo lanzar una excepción? Si lo pones en un comentario de función, debería ser suficiente. Si piensas en algunos programadores específicos que no captan excepciones, tienes que lidiar con PKBAC .


Tengo que aceptar que, en general , es una muy mala idea.

Sin embargo , puedo pensar en uno o dos escenarios donde pueda tener sentido.

Por ejemplo, si está desarrollando un proyecto de biblioteca de clase, es posible que desee lanzar sus propias excepciones personalizadas, y es posible que desee hacer un trabajo adicional siempre que se produzca una de estas excepciones (como el teléfono de la casa si el usuario lo permite).

Para hacer cumplir esto, es posible que desee utilizar un patrón de fábrica, de modo que solo pueda crearlos y obligue a la creación a pasar por un lugar (donde también vive su código "teléfono de hogar").

En este caso, no le gustaría que la fábrica arroje la excepción en sí misma porque eso dejaría el seguimiento de su pila. En cambio, lo devolvería al método original para lanzar.

Pero situaciones como esta son la excepción ** tos ** , en lugar de la regla. Bajo ninguna circunstancia querría que se pasara una excepción a los límites de la biblioteca de la clase, y bajo ninguna circunstancia crearía una excepción sin estar seguro de que se lanzará.


Si te refieres a algo como ...

public Exception MyMethod( string foo ) { if( String.IsNullOrEmpty() ) { return new ArgumentNullException( "foo" ); } }

... más bien que ...

public void MyMethod( string foo ) { if( String.IsNullOrEmpty() ) { throw new ArgumentNullException( "foo" ) } }

Entonces absolutamente no, no está bien hacer eso. Estaría reinventando por completo el propósito de una excepción y usándola como un hresult. Estas son algunas de las mejores prácticas estándar.

Otra buena razón para no hacerlo es que los delegados estándar ya no coincidirían con la firma de su método. Entonces, por ejemplo, ya no podría usar Action<string> en MyMethod y necesitaría usar Func<string,Exception> lugar.

@Andy, por comentario, responde demasiado tiempo para un comentario: en realidad no. No te preocupes por la persona que llama. Debería estar a la defensiva en su diseño de todos modos. Piensa en la semántica de una excepción ... "La ejecución de esta aplicación se detendrá aquí a menos que alguien sepa qué hacer con este problema". Si puede resolver el problema, debe resolverlo. Si no puede hacerlo, debe registrarlo y lanzarlo al siguiente nivel, ya que es posible que sepa exactamente qué hacer.

Debe manejar lo que puede manejar y tirar lo que no puede. Por definición, el chico en la lista de llamadas tiene una visión más amplia del mundo que tú. Su aplicación debe ser resistente en su capacidad para manejar excepciones y seguir funcionando. Lo único que hacen es codificar a la defensiva e impulsar problemas hasta niveles más altos de información para ver si se puede hacer algo.

Al final del día, si la respuesta es "no", entonces se puede entender el problema, se puede ser un buen ciudadano de la caja y terminar la aplicación con gracia y vivir para luchar otro día. No seas egoísta e intenta esconder los errores de tu interlocutor. Ponte a la defensiva y él hará lo mismo. :)

Consulte el bloque de manejo de excepciones de Enterprise Library . Piensan que realmente articulan una gran visión de cómo lidiar con las excepciones en toda su arquitectura.


A menudo devuelvo la excepción usando este patrón para evitar múltiples bloqueos try {} catch que ofuscan el código, así que diría que, en algunos casos, es una buena idea devolver la excepción.

public void Method(string text) { //throw exception if needed throw new Exception("exception"); } public bool TryMethod(string text, out Exception ex) { try { Method("test") ex = null; return true; } catch(Exception e) { ex = e; return false; } }


Las excepciones son solo para situaciones excepcionales. Deje que quien causó el caso excepcional (el que llama) resuelva el problema. Di si tienes un método que divide dos números como

int Div(int x, int y) { return x/y; }

¿Cómo implementaría el manejo correcto de errores para ese método? ¿Qué valor le devolverías a la llamada en los casos a continuación?

Div(10,0); or(int.MinValue,-1); //result of int.MinValue == int.MaxValue + 1;

No hay acción "correcta" en los dos casos, depende del uso del método. En general, es una buena idea romper la ejecución del código cuando surge una situación inesperada.

El manejo de errores es más que try{] catch{} . Todo lo que entra en el bloque catch necesita tomar una decisión sensata basada en el error. Simplemente capturar la excepción y devolverla no es manejo de errores; es un síntoma que se esconde, y hará que la depuración en el mejor de los casos sea muy difícil y, a menudo, una pesadilla.


Estoy de acuerdo en que regresar en lugar de lanzar una excepción es una mala práctica por todos los motivos indicados anteriormente en casi todos los casos excepto en uno, donde el trabajo de las funciones es construir las Excepciones. Por ejemplo, si usa la biblioteca Com que solo devuelve resultados en lugar de generar excepciones, puede crear una función que convierta los resultados en una excepción:

static public ErrorException ReturnErrAsExcep() { int errcd = 0; string errmsg = ""; CrummyComLib.GetLastError(out errcd, out errmsg); ErrorException ex = new SAPErrorException(errmsg, errcd); return ex; }

Que usaría como

int retval = CrummyComObject.DoStuff(); if (retval != 0) throw globals.ReturnErrAsExcep();