try practices handling exceptions example custom catch best c# error-handling error-suppression

practices - Extraño el "Curriculum en caso de error siguiente" de Visual Basic en C#. ¿Cómo debería estar entregando errores ahora?



throw exception c# (6)

Has estado usando esa característica VB mal, y eres tan afortunado que no puedes usarla así en C #.

Cuando se utiliza la función en VB, se supone que debe verificar el estado del error después de cada operación que podría generar un error. Cuando se usa correctamente, no es menos código que try...catch bloques alrededor de cada operación que podría ocasionar un error.

Entonces, si crees que tienes que hacer más manejo de errores en C #, has estado haciendo muy poco manejo de errores antes.

En Visual Basic escribí " On Error Resume Next en el encabezado de mi programa y los errores fueron suprimidos en todo el proyecto.

Aquí en C # echo de menos esta característica. El manejo usual de try-catch para cada procedimiento individual no solo requiere mucho tiempo, sino que también trae efectos no deseados. Si se encuentra un error, incluso si se maneja, el código no continúa desde el momento en que ocurrió. Con On Error Resume Next , el código continuó desde el punto de error, omitiendo solo la llamada a la función que provocó el error.

Todavía no estoy muy involucrado con C #, pero tal vez exista en C # un mejor manejo de errores que el primitivo try-catch .

También me gustaría tener el nombre del módulo o función donde se produjo el error, así como también el número de línea en mi mensaje de error. La clase Exception no proporciona esas características hasta donde yo sé. ¿Alguna idea (administrada, por supuesto, sin involucrar ninguna clase de proceso en mi propia aplicación)?

¿Cómo manejas los errores en proyectos más grandes? Espero no tener que agregar un try-catch a cada método. De alguna manera C # arroja muchos errores, que parece ser típico del lenguaje.

Mi solución que encontré para resolver varios de mis problemas:

public partial class Form1 : Form { public Form1() { InitializeComponent(); } [STAThread] static void Main() { Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); //setup global error handler Application.Run(new Form1()); } private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { MessageBox.Show("Unhandled exception: " + e.Exception.ToString()); //get all error information with line and procedure call Environment.Exit(e.Exception.GetHashCode()); //return the error number to the system and exit the application } private void button1_Click(object sender, EventArgs e) { string s = ""; s.Substring(1, 5); //Produce an error } }


No, no puedes. Esto no es posible en C # (y no debería estar en ningún otro idioma).

El verdadero uso para esto en VB era hacer que el manejo de errores se llevara a cabo en alguna parte del código, al igual que try / catch . Lo habilita, comprueba con Err.Number <> 0 , haga su trabajo y restablezca el flujo de error con On Error GoTo 0 Err.Number <> 0 On Error GoTo 0 o redirija a una etiqueta que sigue una ruta diferente para tratar el error o continuar la ejecución On Error GoTo someErrorCase:

Debe haber aprendido a programar solo o con una persona que no lo hace de la manera correcta. Ignorar los errores es un mal hábito, y más que eso, es algo horrible seguir con el código. Después de todo, los errores son posibles.

Créeme. Yo era un programador de VB y fue esclarecedor cuando me detuve para leer sobre las mejores prácticas.

Solo para agregar algo más, intente utilizar Option Explicit también, puede sonar más trabajo al declarar todas las variables, pero le dará más confianza del código, porque la verificación de tipo limitará algunos errores comunes.

Además, las excepciones de C # son muy útiles y tienen toda la información que pueda desear. Si no tiene el problema con la excepción en sí, simplemente ábrala y mire en su excepción interna (me atrapa siempre buscando las excepciones internas al desarrollar para web, ya que todo el código está en un nivel superior).


"On Error Resume Next" permite "Inline Error Handling", que es el manejo experto de errores de nivel en VB. El concepto es manejar los errores línea por línea, ya sea realizar una acción basada en el error o ignorar el error cuando sea beneficioso, pero ejecutar el código en la secuencia en la que está escrito y no usar saltos de código.

Desafortunadamente, muchos principiantes usaron "En caso de error reanudar a continuación" para ocultar su falta de habilidad o de holgazanería de aquellos que usan sus aplicaciones al ignorar todos los errores. Try / catch es el manejo de errores a nivel de bloque, que en el mundo de pre.NET fue intermedio por diseño e implementación.

El problema con "On Error Resume Next" en VB.NET es que carga el objeto err en cada línea de código de ejecución y, por lo tanto, es más lento que try / catch.

https://msdn.microsoft.com/en-us/library/aa242093(v=vs.60).aspx

Se dice que los programadores intermedios de C # sin experiencia VB real no deberían intentar mantener C # simplificado y tener características limitadas debido a su extraño desdén por otro lenguaje de "Microsoft Net". Considere el siguiente código:

//-Pull xml from file and dynamically create a dataset. string strXML = File.ReadAllText(@"SomeFilePath.xml"); StringReader sr = new StringReader(strXML); DataSet dsXML = new DataSet(); dsXML.ReadXml(sr); string str1 = dsXML.Tables["Table1"].Rows[0]["Field1"].ToString(); string str2 = dsXML.Tables["Table2"].Rows[0]["Field2"].ToStrin(); string str3 = dsXML.Tables["Table3"].Rows[0]["Field3"].ToStrin(); string str4 = dsXML.Tables["Table4"].Rows[0]["Field4"].ToString(); string str5 = dsXML.Tables["Table5"].Rows[0]["Field5"].ToString();

Si el xml generalmente tiene un valor para Field3 pero a veces no; Voy a obtener un error molesto de que la tabla no contiene el campo. Me podría importar menos si no lo hace porque no se requieren datos. En este caso, ON Error Resume Next me permitiría simplemente ignorar el error y no tendría que codificar alrededor de cada línea de código estableciendo las variables comprobando la existencia de la combinación de tabla, fila y columna con los métodos Contiene. Este es un pequeño ejemplo; Podría obtener miles de combinaciones de tablas, columnas y filas de archivos grandes. Además, asuma aquí que las variables de cadena deben ser pobladas de esta manera. Este es un código no controlado y habrá problemas.

Considere un VB.NET y reanudación de error ON Siguiente implementación:

On Error Resume Next Dim strXML As String = File.ReadAllText("SomeNonExistentFileCausingAnErrorCondition.xml") If String.IsNullOrEmpty(strXML) Then strXML = strSomeOtherValidXmlThatIUseWhenTheFileIsEmpty End If Dim srXmL As StringReader = New StringReader(strXML) Dim dsXML As DataSet = New DataSet() dsXML.ReadXml(srXmL) If Err.Number <> 0 Then MsgBox(Err.Number & Space(1) & Err.Description) Exit Sub End If Dim str1 As String = dsXML.Tables("Table1").Rows(1)("Field1").ToString() Dim str2 As String = dsXML.Tables("Table2").Rows(2)("Field2").ToString() Dim str3 As String = dsXML.Tables("Table3").Rows(3)("Field3").ToString() Dim str4 As String = dsXML.Tables("Table4").Rows(4)("Field4").ToString()

En el código anterior, solo era necesario manejar una posible condición de error; aunque hubo un error al cargar el archivo. On Error Resume Next en realidad me permitió reanudar como estaba previsto, lo que me permitió comprobar la condición de la cadena y usar mi cadena alternativa (soy consciente de que también podría haber comprobado la existencia del archivo y evitar el error de archivo, pero era un buen archivo sin nada, strXML sería una cadena vacía). Se manejó el error que era crítico para el resto del código y se salió del método porque el conjunto de datos cargado era primordial para el resto del procesamiento que estaba más allá (procesamiento que podría ejecutarse ignorando cualquier error si así lo desea). El error de archivo podría ignorarse ya que lo ignoré o podría haber verificado la condición de error y haberlo registrado.

Necesidades de desarrollo de RAD al reanudar el error a continuación. C # es mi elección de idiomas, pero no es tanto un lenguaje RAD como VB por muchas razones. Espero que todos los programadores se den cuenta de que varios lenguajes principales (es decir, C) solo se ejecutan y no detienen la ejecución de errores no controlados; el trabajo de los desarrolladores es buscarlos donde lo consideren necesario. On Error Resume Next es lo más parecido a ese paradigma en el mundo de Microsoft.

Afortunadamente, .NET brinda muchas opciones avanzadas para manejar estas situaciones; Eludí a los Contiene. Por lo tanto, en C #, debe reforzar su nivel de conocimiento del idioma y, de acuerdo con la especificación del lenguaje C #, trabajar adecuadamente en torno a estos problemas. Considere una solución para manejar un gran bloque de líneas repetitivas de código que podría contener un molesto error de descarte:

try { if (!File.Exists(@"SomeFilePath.xml")) { throw new Exception("XML File Was Not Found!"); } string strXML = File.ReadAllText(@"SomeFilePath.xml"); StringReader sr = new StringReader(strXML); DataSet dsXML = new DataSet(); dsXML.ReadXml(sr); Func<string, string, int, string> GetFieldValue = (t, f, x) => (dsXML.Tables[t].Columns.Contains(f) && dsXML.Tables[t].Rows.Count >= x + 1) ? dsXML.Tables[t].Rows[x][f].ToString() : ""; //-Load data from dynamically created dataset into strings. string str1 = GetFieldValue("Table1", "Field1", 0); string str2 = GetFieldValue("Table2", "Field2", 0); string str3 = GetFieldValue("Table3", "Field3", 0); //-And so on. } catch (Exception ex) { Debug.WriteLine(ex.Message); }

Aunque en un bloque try / catch, la función lambda está comprobando la existencia de cada combinación de tabla, fila y columna que se extrae del conjunto de datos que fue poblado dinámicamente por el xml. Esto podría verificarse línea por línea, pero requeriría un exceso de código (aquí tenemos la misma cantidad de código de ejecución pero mucho menos código escrito para mantener). Desafortunadamente, esto podría considerarse otra mala práctica de "One Line Functions". Rompo esa regla en el caso de lambdas y funciones anónimas.

Dado que .NET ofrece muchas maneras de verificar el estado de los objetos; En caso de error, el currículum siguiente no es tan vital para los expertos de VB como lo era antes de .NET, pero es bueno tenerlo cerca; especialmente cuando estás codificando algo que sería una pérdida de tiempo no codificar rápido y sucio. Nadie que alguna vez haya usado VB en un nivel experto podría decir que On Error Resume Next (manejo de errores en línea) es la peor característica que se haya agregado a un idioma. Sin embargo, ha sido ampliamente utilizado por los principiantes.


Continuar después de los errores como si nada hubiera pasado es una manera terrible de programar.

No se puede calcular el nuevo saldo de la cuenta? Está bien, simplemente almacénelo como 0. Nadie lo sabrá nunca, ¿verdad?

catch bloques try / catch deberían ser relativamente raros, porque hay relativamente pocos errores de los que realmente puedas recuperarte. Normalmente, debe tener un bloque try / catch en la parte superior de alguna operación lógica, de modo que si falla, puede informar al usuario y continuar con otras operaciones completamente independientes, o finalizar la aplicación por completo, dependiendo del tipo de aplicación que esté escritura. (Las aplicaciones web son un buen ejemplo aquí: puede suspender la solicitud, con la esperanza de tener cuidado de que no tenga desagradables efectos secundarios persistentes, y continuar manejando otras solicitudes).

Donde hay lugares que legítimamente espera errores de los que pueda recuperarse, capture esas excepciones específicas y maneje adecuadamente (por ej., Volver a escribir en un archivo si falla la escritura en una base de datos). Nuevamente, estos son relativamente pocos y distantes. Si te encuentras escribiendo un bloque try / catch en cada método (o incluso en cada clase), entonces probablemente estés manejando excepciones de forma inapropiada.

También me gustaría tener el nombre del módulo o función donde ocurrió el error, así como el número de línea en mi mensaje de error. La clase Exception no proporciona esas características en la medida que experimenté.

Sí lo hace. El rastro de pila muestra el tipo, método y número de línea (donde esté disponible) para cada cuadro en la pila ... así como también un mensaje (con suerte útil), por supuesto. Ah, y potencialmente una excepción anidada también, si una falla fue causada por otra.

De alguna manera C # arroja muchos errores en la ejecución siempre, ese es el lenguaje típico.

No, eso solo sugiere que estás haciendo las cosas mal.


En realidad, las excepciones son más bien la excepción, no ocurren todo el tiempo. Cuando suceden, quiere saber que sucedieron, y ya sea manejarlos o cerrar su proceso. La mayoría de las veces, dejar que una excepción no se maneje va a generar resultados muy inesperados.


No.

Hablando como un ex programador de VB, permítanme asegurarles: esa es la característica peor y más abusada jamás añadida a cualquier idioma. Aquí está la idea en su lugar:

  1. escriba el código que no tenga errores ... a menos que ocurra algo que sea realmente un problema . Esto puede implicar verificar sus suposiciones antes de hacer las cosas; genial: haz eso
  2. solo atrapa los problemas que estabas esperando; tragar todos los errores es solo pedir problemas masivos

Como ya notó Jon, en realidad es bastante raro necesitar manejo de excepciones por todos lados. Por lo general, solo dejas que una excepción llegue a una persona que llama más, porque algo malo simplemente sucedió . Y cuando tengo una try , es más común try / finally (no try / catch ) - con el using y el lock (etc.) siendo casos especiales de aquellos por conveniencia.