Catching base Eccezione per preservare l'integrità dei dati

1

So che spesso catturare tutte le eccezioni (C #: catch(Exception exception){...} ) è considerato una cattiva pratica.

Tuttavia, credo che ci siano situazioni in cui è perfettamente ragionevole farlo. Ad esempio, se ho un numero di operazioni da eseguire:

foreach(var operation in operationBatch)
    operation.Do();

e un batch dovrebbe avere successo nel suo insieme, o fallire nel suo insieme, sembra ragionevole?

var rollBackStack = new Stack<Operation>(operationBatch.Length);
try{
  foreach(var operation in operationBatch)
  {
      operation.Do();
      rollBackStack.Push(operation); // assuming operation is atomic and cannot both apply changes AND fail
  }
} catch(Exception exception) // whatever went wrong...
{
    foreach(var ranOperation in rollBackStack)
      ranOperation.Undo();

    throw; // or throw new MyDomainException("relevant message", exception);
}

Immagino che una versione generica della domanda sarebbe: sta prendendo tutte le eccezioni solo per eseguire qualche azione e rilanciare una pratica accettabile, o c'è un altro modo che è raccomandato? Posso pensare a qualcosa di simile

var completed = 0;
try{
  foreach(var operation in operationBatch)
  {
      operation.Do();
      ++completed;
  }
} finally {
    if(completed != operationBatch.Length)
        foreach(var ranOperation in operationBatch.Take(completed).Reverse())
          ranOperation.Undo();

    // no need to rethrow from finally
}

Ma sembra semplicemente una versione inutilmente più complessa del primo frammento di codice.

    
posta Gerino 09.09.2017 - 00:52
fonte

1 risposta

3

Stai bene.

Dalla documentazione per CA1031 :

CA1031: Do not catch general exception types

Cause

A general exception such as System.Exception or System.SystemException is caught in a catch statement, or a general catch clause such as catch() is used.

How to Fix Violations

To fix a violation of this rule, catch a more specific exception, or rethrow the general exception as the last statement in the catch block.

Sembra che la guida su questa particolare regola sia che va bene prendere un'eccezione generale finché la si ripete. Il tuo design è coerente con questa guida.

Nota: c'è una differenza significativa tra queste due affermazioni:

throw; 

throw new MyDomainException("relevant message", exception);

Nella maggior parte dei casi dovresti usare il primo, che conserva la traccia dello stack e il tipo di eccezione originale in modo che i blocchi catch "esterni" possano distinguere tra un errore di sistema come la memoria esaurita (che di solito non vorranno catturare, poiché non può davvero gestirli) ed eccezioni di dominio (che probabilmente possono).

    
risposta data 09.09.2017 - 02:18
fonte

Leggi altre domande sui tag