dichiarare un metodo genera sempre un’eccezione?

Ho un metodo come …

int f() { try { int i = process(); return i; } catch(Exception ex) { ThrowSpecificFault(ex); } } 

Ciò produce un errore del compilatore, “non tutti i percorsi di codice restituiscono un valore”. Ma nel mio caso ThrowSpecificFault () genererà sempre l’eccezione (appropriata). Quindi sono costretto a mettere un valore di ritorno alla fine, ma questo è brutto.

Lo scopo di questo modello in primo luogo è perché “process ()” è una chiamata a un servizio Web esterno, ma è necessario tradurre una varietà di diverse eccezioni per far corrispondere l’interfaccia prevista del client (~ pattern di facciata suppongo).

Qualche modo più pulito per farlo?

    Suggerisco di convertire ThrowSpecificFault(ex) per throw SpecificFault(ex) ; il metodo SpecificFault restituirebbe l’object eccezione da lanciare anziché lanciare esso stesso. Molto più pulito

    Questo è il modello raccomandato dalle linee guida di Microsoft (trovare il testo “Usa i metodi del generatore di eccezioni”).

    Il problema qui è che se entrate nel blocco catch in f() vostra funzione non restituirà mai un valore. Ciò si tradurrà in un errore perché hai dichiarato la tua funzione come int che significa che hai detto al compilatore che il tuo metodo restituirà un intero.

    Il seguente codice farà ciò che stai cercando e restituirà sempre un numero intero.

     int f() { int i = 0; try { i = process(); } catch(Exception ex) { ThrowSpecificFault(ex); } return i; } 

    metti la dichiarazione di ritorno alla fine della tua funzione e starai bene.

    È sempre una buona idea assicurarsi che il metodo restituisca sempre un valore indipendentemente dal percorso di esecuzione della tua applicazione.

    In questo momento un tipo di ritorno può essere un tipo, o “vuoto” che significa “nessun tipo di ritorno”. Potremmo in teoria aggiungere un secondo tipo di ritorno speciale “mai”, che ha la semantica desiderata. Il punto finale di un’espressione di espressione consistente in una chiamata a un metodo di “non ritorno” sarebbe considerato irraggiungibile, e quindi sarebbe legale in ogni contesto in C # in cui un “goto”, “throw” o “return” è legale .

    È altamente improbabile che questo verrà aggiunto al sistema di tipi ora, dieci anni dopo. La prossima volta che si progetta un sistema di tipi da zero, ricordarsi di includere un tipo “mai”.

    No.

    Immagina se ThrowSpecificFault fosse definito in una DLL separata. Se modifichi la DLL per non generare un’eccezione, quindi esegui il tuo programma senza ricompilarlo, cosa succederebbe?

    Puoi fare così:

     catch (Exception ex) { Exception e = CreateSpecificFault(ex); throw e; } 

    Hai tre opzioni:

    Restituiscimi sempre ma pre-dichiaro:

     int f() { int i = 0; // or some other meaningful default try { i = process(); } catch(Exception ex) { ThrowSpecificFault(ex); } return i; } 

    Restituisce l’eccezione dal metodo e lancia quello:

     int f() { try { int i = process(); return i; } catch(Exception ex) { throw GenerateSpecificFaultException(ex); } } 

    Oppure crea una class Exception personalizzata e lancia quella:

     int f() { try { int i = process(); return i; } catch(Exception ex) { throw new SpecificFault(ex); } } 

    Che ne dite di:

     int f() { int i = -1; try { i = process(); } catch(Exception ex) { ThrowSpecificFault(ex); } return i; } 

    Sì.

    Non aspettarti che ThrowSpecificFault () generi l’eccezione. Fallo restituire l’eccezione, quindi gettalo qui.

    In realtà ha anche più senso. Non si utilizzano eccezioni per il stream “normale”, quindi se si genera un’eccezione ogni volta, l’eccezione diventa la regola. Crea l’eccezione specifica nella funzione e buttala qui perché è un’eccezione al stream qui ..

    Suppongo che potresti rendere ThrowSpecificFault restituire un object, e quindi potresti farlo

     return ThrowSpecificFault(ex) 

    Altrimenti, potresti riscrivere ThrowSpecificFault come costruttore per un sottotipo Exception, oppure potresti semplicemente trasformare ThrowSpecificFault in una factory che crea l’eccezione ma non la butta.

    Nel tuo caso, ma questa è la tua conoscenza, non il compilatore. C’è ora modo di dire che questo metodo creerà sicuramente qualche brutta eccezione.

    Prova questo

     int f() { try { return process(); } catch(Exception ex) { ThrowSpecificFault(ex); } return -1; } 

    Puoi anche usare la parola chiave di lancio

     int f() { try { return process(); } catch(Exception ex) { throw ThrowSpecificFault(ex); } } 

    Ma allora quel metodo dovrebbe restituire qualche eccezione invece di lanciarlo.

    Utilizzare Unity.Interception per pulire il codice. Con la gestione delle intercettazioni, il tuo codice potrebbe assomigliare a questo:

     int f() { // no need to try-catch any more, here or anywhere else... int i = process(); return i; } 

    Tutto quello che devi fare nel passaggio successivo è definire un gestore dell’intercettazione, che puoi personalizzare su misura per la gestione delle eccezioni. Usando questo gestore, puoi gestire tutte le eccezioni generate nella tua app. Il vantaggio è che non è più necessario contrassegnare tutto il codice con blocchi try-catch.

     public class MyCallHandler : ICallHandler, IDisposable { public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { // call the method var methodReturn = getNext().Invoke(input, getNext); // check if an exception was raised. if (methodReturn.Exception != null) { // take the original exception and raise a new (correct) one... CreateSpecificFault(methodReturn.Exception); // set the original exception to null to avoid throwing yet another // exception methodReturn.Exception = null; } // complete the invoke... return methodReturn; } } 

    La registrazione di una class al gestore può essere eseguita tramite un file di configurazione o a livello di programmazione. Il codice è abbastanza semplice. Dopo la registrazione, istanzia gli oggetti usando Unity, in questo modo:

     var objectToUse = myUnityContainer.Resolve(); 

    Altro su Unity.Interception:

    http://msdn.microsoft.com/en-us/library/ff646991.aspx