¿Cómo decidir entre usar if / else vs try / catch?

Al escribir el código, ¿cómo se decide entre usar if / else o try / catch? Por ejemplo, al verificar un archivo, ¿debería basarse en si / else (if (File.Exists)) o un bloque try / catch?

Por ejemplo, escribir en un archivo se puede manejar a través de un bloque if / else para crear un archivo y luego escribir en él, o un bash / captura con el supuesto de que el archivo existe. ¿Qué consideraciones hay en la elección?

Gracias

Nunca debe usar try / catch para el control de flujo.

Generar una excepción es una acción extremadamente costosa. Si / else es mucho más rápido y más limpio.

Siempre debe usar try / catch cuando trabaja con archivos, ya que el estado de un archivo puede cambiar fuera de su progtwig.

Considere el siguiente bit de código:

if(File.Exists("file.txt")) File.Delete("file.txt") 

El archivo podría haber sido eliminado por otro proceso justo después de la instrucción if, antes de la llamada Delete() . Cuando intenta borrarlo, se genera una excepción.

Al trabajar con archivos, también hay muchas más cosas que considerar, que es posible que no pueda detectar con ifs, por ejemplo, el archivo se encuentra en una conexión de red que no está disponible, derechos de acceso que cambian, falla del disco duro, etc.

Estas cosas están fuera del control de su progtwig, por lo que debe tener manejadores de excepciones en su lugar.

Si cree que la operación normalmente debería tener éxito, entonces try/catch puede ser más fácil de leer. Especialmente, si hay muchas razones para fallar (múltiples bloques de catch ).

De lo contrario, si a veces tiene éxito y otras veces falla, y lo hace por una razón específica, use if/else (esto se conoce como manejo estructurado de excepciones).

Algunas personas señalan cómo el manejo de excepciones con try/catch puede llevar mucho tiempo. Tiendo a leer consejos como esos en las siguientes líneas: No haga esto en un bucle interno estrecho, si su perfil indica un problema de rendimiento. Cuando codifique su primer borrador, ¡no se moleste en pensar en optimizar a este nivel!

Utiliza try / catch cuando algo inesperado (una excepción) puede suceder y quieres hacer algo especial al respecto, como:

 try { //Do something that might rise an exception, say a division by 0 //this is just an easy example as you might want to check if said value is not 0 //before dividing int result = someNumberOfMine / anUnsafeNumber; } catch { //if something unexpected happened, do a special treament } 

En su caso particular, recomiendo usar File.Exists para verificar la presencia del archivo en lugar de usar un bloque try / catch ya que la presencia o no del archivo se puede verificar antes de hacer algo con él.

Solo para dejar el tema en reposo (sí, la pregunta fue planteada hace 8 meses, ¡pero Internet siempre lo sabe!), Decidí realizar una pequeña prueba, la cual es más eficiente si está bastante seguro de que no tendrá una excepción: por ejemplo, la parte “else” solo ocurrirá el 0.001% del tiempo. Resulta que, si nunca tienes que atrapar / si no algo, el try-catch es aproximadamente un 4% más rápido (en mi máquina, de todos modos). Aquí está el código y los resultados que acompañan:

CASO 1: si-si no

 var startTime = DateTime.Now; int bazillion = 100000000; int[] list = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; for (int i = 0; i < bazillion; i++) { for (int k = 0; k < list.Length; k++) { if (k >= 0) { list[k] = i; } else { // do nothing. } } } var executionTime = DateTime.Now - startTime; Debug.WriteLine (executionTime.TotalMilliseconds); 

Tiempos de ejecución (milisegundos) en 5 ejecuciones: 7441.4256, 7392.4228, 7545.4316, 7531.4308, 7323.4188.
Promedio = 7446.82592 milisegundos

CASO 2: try-catch:

 var startTime = DateTime.Now; int bazillion = 100000000; int[] list = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; for (int i = 0; i < bazillion; i++) { for (int k = 0; k < list.Length; k++) { try { list[k] = i; } catch (Exception e) { // do nothing } } } var executionTime = DateTime.Now - startTime; Debug.WriteLine(executionTime.TotalMilliseconds); 

Tiempos de ejecución (milisegundos) en 5 ejecuciones: 7258.4152, 7137.4083, 7070.4044, 7052.4033, 7120.4073 Promedio = 7127.8077 milisegundos

Conclusión (basado en este ejemplo bastante simplista; el kilometraje real puede variar, etc.) :
En términos de números absolutos, si está bastante seguro de que no se producirá el caso de excepción / caso contrario, try-catch es aproximadamente un 4% más rápido que tener que ejecutar la cláusula "si" cada vez.

El manejo excepcional solo debe hacerse o usarse en casos excepcionales.

En un escenario que depende de si un archivo existe o no, no tiene sentido usar el bloque try catch cuando simplemente puede hacerlo

 if(File.Exists(path)) { } else { } 

El manejo excepcional causa muchos impactos en el rendimiento, así que intente minimizar los casos excepcionales aplicando más control en su código como si File.Exists(path))

en general depende

Para las cosas basadas en archivos, casi siempre desea probar la operación y manejar las fallas en lugar de verificar primero. La razón es que el sistema de archivos es un recurso compartido y no puede garantizar que después de que file.exists devuelva true, el archivo existe, ya que es posible que algún otro proceso lo haya eliminado.

Como ya han señalado algunas respuestas, depende.

Si / else se usa para el control de flujo, pero también se pueden hacer excepciones con la ventaja adicional de detectar un error que ocurra. Pero como Turowicz señaló, se considera una mala práctica para muchas personas, usar el método try / catch más que el mínimo de lo que tienes que hacer.

Siempre puede leer estos artículos de Ned Batchelder (Habla sobre los códigos de retorno, como alternativa al uso de excepciones) y Joel Spolsky (Por qué no le gusta progtwigr con excepciones) para tener una idea de lo que otros piensan de las excepciones y luego hacer su propia mente para arriba

Solo un pensamiento … una de las respuestas fue que deberías hacer una captura de prueba si, por ejemplo, tienes una posibilidad de división por cero. ¿Me pregunto porque? Usted tiene el control aquí, puede verificar antes de dividir y actuar. Si es cero, simplemente no necesitas hacer la división, sino ejecutar otra lógica.

Solo usaría try catch en el caso de que usted no tenga el control o no pueda (o no tenga sentido) verificar las cosas de antemano (abrir un archivo, …).

En su caso, usaría File.Exists y try / catch. File.Existes como un cheque de negocios (no es necesario abrirlo cuando no existe), intente / atrape para detectar cualquier excepción que pueda ocurrir al abrir el archivo.

Cuando se espera que el archivo no exista, verifique la existencia primero. Pero cuando el archivo que falta es un estado inusual, debe indicar este estado excepcional con una excepción.

Así que la idea básica es: tratar de evitar excepciones en circunstancias esperadas.

Generalmente deberías hacer ambas cosas. Intentar / atrapar para evitar situaciones excepcionales (el archivo se eliminó repentinamente de otro hilo). Y si / else para manejar no excepcional (verifique si existe el archivo). Probar / atrapar es relativamente más lento de lo habitual si / else, por lo que no vale la pena usarlo para todo.

El adagio “Las excepciones deben ser excepcionales” es útil al tomar este tipo de decisiones. El principal es que debe manejar situaciones conocidas con un flujo de progtwig estándar (es decir, declaraciones) para que las excepciones representen situaciones inesperadas (es decir, errores).

Por supuesto, como cualquier regla, está ahí para ser roto.

Además, no me preocuparía demasiado el impacto en el rendimiento del manejo de excepciones. La sobrecarga es bastante insignificante en todas las situaciones, excepto en situaciones extremas.

Para esto sabes el problema de salida de archivo. Así que prefieres que si no.

Si no conoce el problema, es mejor usar la captura de prueba.

sugiero los dos, como abajo

 try { if(File.Exists(path)) { do work } else { messagebox.show("File Path Not Exit"); } } catch(Exception e) { messagebox.show(e); } 

Atrapa todos los errores, que no pensamos.

Como es obvio por todas las respuestas, no hay una forma estándar / aprobada para decidir si debe usar una u otra. Si se hace correctamente, ambos métodos serán efectivos. Si se hace incorrectamente, ambos métodos serán ineficientes.

Prefiero las sentencias if / else cuando es significativa (es decir, dentro de mis propias funciones) y los bloques Try cuando invoco funciones sobre las que no tengo control.

En el ejemplo anterior, File.Exists () sería suficiente si controla el archivo (lo que significa que no es probable que otro progtwig lo manipule), pero no lo suficiente si existe la posibilidad de que el archivo pase entre la verificación y el uso.

Las operaciones de archivos, en general, se manejan mejor con excepciones en la mayoría de los casos, según mi experiencia, porque estas mismas operaciones de archivos, en c #, están generando excepciones. No devuelven códigos de error que puedan verificarse con declaraciones.