2010-03-03 11 views
7

En Python, no es esto útil código de control de excepciones:C#: Equivalente del intento pitón/catch/else bloquear

try: 
    # Code that could raise an exception 
except Exception: 
    # Exception handling 
else: 
    # Code to execute if the try block DID NOT fail 

Creo que es útil ser capaz de separar el código que podía aumento y excepción de su código normal. En Python, esto fue posible como se muestra arriba, sin embargo, no puedo encontrar nada parecido en C#.

Asumiendo que la característica o una similar no existe, ¿es una práctica estándar poner código normal en el bloque try o después del bloque catch?

La razón que pido es porque tengo el siguiente código:

if (!IsReadOnly) 
{ 
    T newobj; 
    try 
    { 
     newobj = DataPortal.Update<T>(this); 

     List<string> keys = new List<string>(BasicProperties.Keys); 
     foreach (string key in keys) 
     { 
      BasicProperties[key] = newobj.BasicProperties[key]; 
     } 
    } 
    catch (DataPortalException) 
    { 
     // TODO: Implement DataPortal.Update<T>() recovery mechanism 
    } 
} 

que requiere el código normal estar en el bloque try porque de lo contrario, si se produce una excepción y, posteriormente, manejado, newobj habría asignado, pero se siente bastante antinatural tener este código en el bloque try que no está relacionado con el DataPortalException. ¿Qué hacer?

Gracias

+1

Siempre he odiado el uso de bloques intento de captura debido a esto. No hay forma de separar el código de interrupción y no se rompió el código. –

+1

Votación para cerrar como duplicado exacto: http://stackoverflow.com/questions/1177438/c-try-catch-else – ChristopheD

+0

Esto podría ser un duplicado, pero esa pregunta nunca fue respondida lo suficiente. Después de leer las respuestas, me gusta más el concepto de Daniel Newby. –

Respuesta

0

se podría hacer algo como esto:

if (!IsReadOnly) 
{ 
    T newobj = null; 
    try 
    { 
     newobj = DataPortal.Update<T>(this);  
    } 
    catch (DataPortalException) 
    { 
     // TODO: Implement DataPortal.Update<T>() recovery mechanism 
    } 
    if (newobj != null) 
    { 
     List<string> keys = new List<string>(BasicProperties.Keys); 
     foreach (string key in keys) 
     { 
      BasicProperties[key] = newobj.BasicProperties[key]; 
     } 
    } 
} 
0

que sería la sentencia vacía como éxitos

try 
{ 
    somethingThatCanThrow(); 
} 
catch(Exception ex) 
{ 
    LogException(ex); 
    return; 
} 
ContinueFlow(); 
8

yo preferiría ver el resto del código fuera de la try/catch para que quede claro de dónde viene la excepción que está tratando de atrapar y que no atrape accidentalmente una excepción que no estaba tratando de atrapar.

Creo que el equivalente más cercano al Python try/catch/else es usar una variable booleana local para recordar si se lanzó o no una excepción.

bool success; 

try 
{ 
    foo(); 
    success = true; 
} 
catch (MyException) 
{ 
    recover(); 
    success = false; 
} 

if (success) 
{ 
    bar(); 
} 

Pero si usted está haciendo esto, me pregunto por qué no se recupera totalmente, ya sea de la excepción para que pueda continuar como si no hubiera habido éxito, o bien totalmente abortar devolviendo un código de error o simplemente dejando que la excepción se propague a la persona que llama.

+1

+1 para la parte 'manejar la excepción correctamente'. Si no puede recuperarse de la excepción, probablemente deba dejar de hacer lo que está haciendo inmediatamente. Si no puede detenerse con gracia, refactorice para que pueda hacerlo. – kibibu

+1

+1, pero tengo que preguntar: ¿cómo es esto mejor que poner la llamada en la barra() justo antes de la captura? –

+1

@David: con el código que di, si la función 'bar' arroja una MyException, entonces no será capturada, pero con su sugerencia será atrapada. El método que mostré más de cerca coincide con el constructo 'try: catch: else:' en el sentido de que las excepciones planteadas en 'else' no se detectan. –

2

C# no tiene un concepto de este tipo, por lo que sólo se quedan con tres opciones,

  • poner el código más dentro del intento.
  • pon el código else fuera del bloque try catch, usa una variable local para indicar el éxito o el fracaso, y un bloque if en torno a tu código else.
  • pon el código else en el bloque finally, usa una variable local para indicar el éxito o el fracaso, y un bloque si otro código.
2

Simplemente ponga su bloque "else" antes de la captura. Entonces, sólo se ejecutará si la ejecución de código llega a ese punto:

try 
{ 
    fee(); 
    fi(); 
    foe(); 
    fum(); 

    /// put your "else" stuff here. 
    /// It will only be executed if fee-fi-foe-fum did not fail. 
} 
catch(Exception e) 
{ 
    // handle exception 
} 

Teniendo en cuenta que, no llego a ver el uso de try..catch ... otra cosa a menos que haya algo vital faltante de la descripción de la OP.

+5

La diferencia es que hay 1 línea que se espera que genere una excepción y usted espera que eso pueda suceder y atraparla. Si una línea diferente arrojó la excepción que podría ser algo que no desea atrapar, porque puede indicar un error real. – Davy8

+0

@ Davy8 en ese caso, usted debe a) capturar solo el tipo de excepción específica que espera, o b) poner el código que no espera generar una excepción ** fuera ** de este try..catch bloquear. En cualquier caso, aún debe detectar cualquier excepción que ocurra para que pueda fallar con elegancia. –

+1

Está cerca, pero no es completamente equitativo. Si está justo fuera del try/catch, se ejecutará independientemente de si la primera sección arrojó una excepción, pero solo debería ejecutarse cuando la primera parte no se lanzó. Es posible que se pueda lanzar el mismo tipo de excepción, por lo que simplemente capturar una excepción específica es una mejora, pero no es exactamente lo mismo. – Davy8

2

Permítame repetir una idea de similar StackOverflow question. No puede hacer esto directamente, pero puede escribir un método que encapsule el comportamiento que necesita. Mire la pregunta original para ver cómo implementar el método (si no está familiarizado con las expresiones lambda y los delegados Func). El uso podría tener este aspecto:

TryExceptRaise(() => { 
    // code that can throw exception 
    }, (Exception e) => { 
    // code to run in case of an exception 
    return (...); 
    },() => { 
    // code to run if there is no exception 
    return (...); 
    }); 
6

solución Barbaric: crear una clase Else derivado de Excepción, lanzar una instancia del mismo al final del bloque try, y utilizar catch (Else) {...} para manejar las otras cosas.

Me siento tan sucio.

+3

No sé qué hacer aquí - esto * exige * un voto de -1, pero me divierto lo suficiente como para dudar en hacerlo. –

+1

Else en python no capta todas las demás excepciones. De lo contrario, solo se ejecuta cuando no hay excepciones. – Nate

3

Esto puede ser downvoted pero no C# tiene goto (tenga en cuenta que casi no tengo conocimiento de C#, así que no tengo idea de si esto funciona).

¿qué pasa con algo así como

try 
{ 
... 
} 
catch(Exception ex) 
{ 
... 
goto Jump_past_tryelse 
} 
...//Code to execute if the try block DID NOT fail 

Jump_past_tryelse: 
... 
+0

¡Casi te di un +1 simplemente por ofrecer todo el pub con tu 'goto'! – amelvin

+0

Solo casi, cuenta. – amelvin

+3

"ofreciendo todo el pub" ==? –

0
if (!IsReadOnly) 
     { 
      T newobj; 
      bool Done; 
      try 
      { 
       newobj = DataPortal.Update<T>(this); 
       List<string> keys = new List<string>(BasicProperties.Keys); 
       foreach (string key in keys) 
       { 
        BasicProperties[key] = newobj.BasicProperties[key]; 
       } 
       Done = true; 
      } 
      catch (DataPortalException) 
      { 
       // TODO: Implement DataPortal.Update<T>() recovery mechanism 
       Done = false; 
      } 
      finally 
      { 
       if (newobj != null && Done == false) 
       { 
        List<string> keys = new List<string>(BasicProperties.Keys); 
        foreach (string key in keys) 
        { 
         BasicProperties[key] = newobj.BasicProperties[key]; 
        } 
       } 
      } 
     } 
0

Con C# versión 7, podría utilizar funciones locales emular este comportamiento:

Ejemplo 1:

void Main() 
{ 
    void checkedCode() 
    { 
     try 
     { 
      foo(); 
     } 
     catch (Exception ex) 
     { 
      recover(); 
      return; 
     } 
     // ElseCode here 
    } 
    checkedCode(); 
} 

Si prefiere sintaxis lambda, también se puede declarar un método run

void Run(Action r) { r(); } 

que sólo tiene que estar allí una vez en su código, y luego usar el modelo para los métodos anónimos de la siguiente manera

ejemplo 2:

Run(() => { 
    try 
    { 
     foo(); 
    } 
    catch (Exception) 
    { 
     recover(); 
     return; 
    } 
    // ElseCode here 
}); 

dondequiera que usted necesita para encerrar el código en un contexto seguro.


Notas:

  • En ambos ejemplos se crea un contexto función de manera que podemos utilizar return; para salir en caso de error.
  • Un patrón similar al utilizado en Ejemplo 2 lo puede encontrar en JavaScript: Self-invoking anonymous functions (por ejemplo, JQuery los usa). Debido a que en C# no se puede invocar a sí mismo, se usa el método de ayuda Run.
  • Desde Run no tiene que ser una función local, Ejemplo 2 funciona con versiones anteriores de C#, así