2010-03-03 14 views
7

In Python, c'è questo utile codice di gestione delle eccezioni:C#: Equivalente del try pitone/catch/altro blocco

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

Penso che sia utile essere in grado di separare il codice che poteva aumento e eccezione dal tuo codice normale. In Python, questo era possibile come mostrato sopra, tuttavia non riesco a trovare nulla di simile in C#.

Supponendo che la funzione o una come non esista, è prassi normale inserire il codice normale nel blocco try o dopo il blocco catch?

Il motivo che mi chiedo è perché ho il seguente codice:

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 
    } 
} 

che richiede il codice normale essere nel blocco try perché altrimenti se un'eccezione è stata sollevata e successivamente gestito, newobj sarebbe assegnato, ma è abbastanza innaturale avere questo codice nel blocco try che non è correlato allo DataPortalException. Cosa fare?

Grazie

+1

ho sempre odiato usando blocchi try di cattura a causa di questo. Non c'è modo di separare il codice di break-off e non ha infranto il codice. –

+1

Votazione per chiudere come duplicato esatto: http://stackoverflow.com/questions/1177438/c-try-catch-else – ChristopheD

+0

Questo potrebbe essere un duplicato, ma tale domanda non ha mai ricevuto risposta sufficiente. Dopo aver letto le risposte, mi piace il concetto di Daniel Newby. –

risposta

0

Si potrebbe fare qualcosa di simile:

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

che sarebbe la dichiarazione vuota come colpi

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

preferirei vedere il resto del codice al di fuori del prova/cattura, quindi è chiaro da dove proviene l'eccezione che stai cercando di catturare e che non accidentalmente trovi un'eccezione che non stavi cercando di catturare.

Penso che l'equivalente più vicino a Python try/catch/else sia quello di utilizzare una variabile booleana locale per ricordare se è stata generata o meno un'eccezione.

bool success; 

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

if (success) 
{ 
    bar(); 
} 

Ma se si sta facendo questo, mi piacerebbe chiedere il motivo per cui non si recuperano sia pienamente l'eccezione in modo che sia possibile continuare come se non ci fosse stato il successo, oppure completamente interrompe restituendo un codice di errore o anche solo lasciare che l'eccezione si propaghi al chiamante.

+1

+1 per la parte 'gestisci l'eccezione correttamente'. Se non riesci a recuperare dall'eccezione, probabilmente dovresti smettere di fare ciò che stai facendo immediatamente. Se non riesci a fermarti con grazia, il refattore è così che puoi. – kibibu

+1

+1, ma devo chiederlo: com'è meglio che mettere la chiamata a bar() subito prima della cattura? –

+1

@David: Con il codice che ho dato, se la funzione 'bar' lancia una MyException allora non verrà catturata ma con il tuo suggerimento verrà catturata. Il metodo che ho mostrato più fedelmente corrisponde al costrutto try: catch: else: 'in quanto le eccezioni sollevate nel' else' non vengono catturate. –

2

C# non ha un tale concetto, quindi si è appena lasciato con tre opzioni,

  • mettere il codice altro all'interno della prova.
  • inserire il codice else all'esterno del blocco catch try, utilizzare una variabile locale per indicare il successo o l'insuccesso e un blocco if nel codice else.
  • inserire il codice else nel blocco finally, utilizzare una variabile locale per indicare l'esito positivo o negativo e un blocco if per il codice else else.
2

Basta inserire il blocco "else" prima del il fermo. Poi, si eseguirà solo se l'esecuzione di codice raggiunge quel 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 
} 

Dato che, non riesco a vedere l'uso di try..catch ... altro a meno che non ci sia qualcosa di vitale manca dalla descrizione del PO.

+5

La differenza è che c'è una riga che è prevista lanciare un'eccezione e ti aspetti che ciò possa accadere e prenderlo. Se una linea diversa ha lanciato l'eccezione che potrebbe essere qualcosa che non vuoi prendere, perché potrebbe indicare un bug reale. – Davy8

+0

@ Davy8 in questo caso, dovresti essere a) prendere solo il tipo di eccezione specifico che ti aspetti, oppure b) inserire il codice che non ti aspetti di generare un'eccezione ** al di fuori ** di questo try..catch bloccare. In ogni caso, dovresti comunque rilevare eventuali eccezioni che si verificano in modo da poter fallire con garbo. –

+1

È vicino, ma non è abbastanza equivoco. Se è appena fuori dal try/catch, verrà eseguito indipendentemente dal fatto che la prima sezione abbia generato un'eccezione, ma dovrebbe essere eseguita solo quando la prima parte non viene lanciata. È possibile che sia possibile lanciare lo stesso tipo di eccezione, quindi limitarsi a rilevare un'eccezione specifica è un miglioramento, ma non è esattamente la stessa cosa. – Davy8

2

Consentitemi di ripetere un'idea da un similar StackOverflow question. Non puoi farlo direttamente, ma puoi scrivere un metodo che incapsula il comportamento di cui hai bisogno. Osserva la domanda originale per vedere come implementare il metodo (se non hai familiarità con espressioni lambda e delegati Func). L'utilizzo potrebbe assomigliare a questo:

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

soluzione Barbaric: creare una classe derivata da Exception Else, lanciare un'istanza alla fine del blocco try, e utilizzare catch (Else) {...} per gestire le altre cose.

Mi sento così sporco.

+3

Non so cosa fare qui - questo * richiede * un voto di -1, ma sono divertito abbastanza da esitare a farlo. –

+1

Altrimenti in python non cattura tutte le altre eccezioni. Altrimenti, viene eseguito solo quando non sono presenti eccezioni. – Nate

3

Questo potrebbe essere downvoted ma non C# ha goto (nota che non ho quasi nessuna conoscenza di C# quindi non ho idea se questo funziona).

che dire qualcosa di simile

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

Jump_past_tryelse: 
... 
+0

Ti ho quasi dato un +1 semplicemente per offrire l'intero pub con il tuo 'goto'! – amelvin

+0

Solo quasi, attenzione. – amelvin

+3

"offrire l'intero 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# versione 7, si potrebbe usare funzioni locali per emulare questo comportamento:

Esempio 1:

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

Se si preferisce sintassi lambda, si potrebbe anche dichiarare un metodo run

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

che ha solo bisogno di essere lì una volta nel codice, e quindi utilizzare il modello per i metodi anonimi come segue

esempio 2:

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

dovunque è necessario racchiudere il codice in un contesto di sicurezza.


Note:

  • In entrambi gli esempi un contesto funzione viene creato in modo che possiamo utilizzare return; per uscire in caso di errore.
  • Un modello simile a quello utilizzato in Esempio 2 è possibile trovare in JavaScript: Self-invoking anonymous functions (ad esempio, JQuery li utilizza). Poiché in C# non puoi autoinvocare, viene utilizzato il metodo helper Run.
  • Dal Run non deve essere una funzione locale, Esempio 2 funziona con le versioni più vecchie # C così
Problemi correlati