Question Pourquoi attraper et relancer une exception en C #?


Je regarde l'article C # - Objet de transfert de données sur les DTO sérialisables.

L'article comprend ce morceau de code:

public static string SerializeDTO(DTO dto) {
    try {
        XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
        StringWriter sWriter = new StringWriter();
        xmlSer.Serialize(sWriter, dto);
        return sWriter.ToString();
    }
    catch(Exception ex) {
        throw ex;
    }
}

Le reste de l'article semble sain et raisonnable (à un noob), mais que try-catch-throw lève une exception WtfException ... N'est-ce pas exactement équivalent à ne pas gérer les exceptions du tout?

Ergo:

public static string SerializeDTO(DTO dto) {
    XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
    StringWriter sWriter = new StringWriter();
    xmlSer.Serialize(sWriter, dto);
    return sWriter.ToString();
}

Ou est-ce que je manque quelque chose de fondamental à propos de la gestion des erreurs en C #? C'est à peu près la même chose que Java (sauf les exceptions vérifiées), n'est-ce pas? ... Autrement dit, ils ont tous deux affiné le C ++.

La question Stack Overflow La différence entre relancer la capture sans paramètre et ne rien faire? semble soutenir ma prétention que try-catch-throw est-un no-op.


MODIFIER:

Juste pour résumer pour tous ceux qui trouvent ce fil à l'avenir ...

NE PAS

try {
    // Do stuff that might throw an exception
}
catch (Exception e) {
    throw e; // This destroys the strack trace information!
}

Les informations de trace de la pile peuvent être cruciales pour identifier la cause première du problème!

FAIRE

try {
    // Do stuff that might throw an exception
}
catch (SqlException e) {
    // Log it
    if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
        // Do special cleanup, like maybe closing the "dirty" database connection.
        throw; // This preserves the stack trace
    }
}
catch (IOException e) {
    // Log it
    throw;
}
catch (Exception e) {
    // Log it
    throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
    // Normal clean goes here (like closing open files).
}

Attrapez les exceptions les plus spécifiques avant les moins spécifiques (comme Java).


Les références:


444
2018-05-19 07:56


origine


Réponses:


Premier; la façon dont le code dans l'article le fait est mauvais. throw ex réinitialisera la pile d'appels dans l'exception au point où cette instruction throw est; perdre l'information sur l'endroit où l'exception a été créée.

Deuxièmement, si vous attrapez et relancez comme ça, je ne vois pas de valeur ajoutée, l'exemple de code ci-dessus serait aussi bon (ou, étant donné le throw ex peu, encore mieux) sans l’essayage.

Cependant, il y a des cas où vous pourriez vouloir attraper et renvoyer une exception. La journalisation pourrait être l'une d'entre elles:

try 
{
    // code that may throw exceptions    
}
catch(Exception ex) 
{
    // add error logging here
    throw;
}

349
2018-05-19 08:02



Ne fais pas ça,

try 
{
...
}
catch(Exception ex)
{
   throw ex;
}

Vous perdrez les informations de trace de la pile ...

Ou bien,

try { ... }
catch { throw; }

OU

try { ... }
catch (Exception ex)
{
    throw new Exception("My Custom Error Message", ex);
}

Une des raisons pour lesquelles vous pourriez vouloir relancer est si vous gérez des exceptions différentes, pour par exemple.

try
{
   ...
}
catch(SQLException sex)
{
   //Do Custom Logging 
   //Don't throw exception - swallow it here
}
catch(OtherException oex)
{
   //Do something else
   throw new WrappedException("Other Exception occured");
}
catch
{
   System.Diagnostics.Debug.WriteLine("Eeep! an error, not to worry, will be handled higher up the call stack");
   throw; //Chuck everything else back up the stack
}

97
2018-05-19 08:03



C # (avant C # 6) ne prend pas en charge les "exceptions filtrées" CIL, ce que fait VB. En C # 1-5, une des raisons pour relancer une exception est que vous n'avez pas assez d'informations au moment de catch () pour déterminer si vous voulez réellement attraper l'exception.

Par exemple, dans VB, vous pouvez faire

Try
 ..
Catch Ex As MyException When Ex.ErrorCode = 123
 .. 
End Try

... qui ne gère pas les MyExceptions avec des valeurs ErrorCode différentes. En C # avant la v6, vous devrez intercepter et relancer la MyException si le ErrorCode n'était pas 123:

try 
{
   ...
}
catch(MyException ex)
{
    if (ex.ErrorCode != 123) throw;
    ...
}

Depuis C # 6.0, vous pouvez filtrer tout comme avec VB:

try 
{
  // Do stuff
} 
catch (Exception e) when (e.ErrorCode == 123456) // filter
{
  // Handle, other exceptions will be left alone and bubble up
}

48
2018-05-19 08:20



Ma principale raison pour avoir du code comme:

try
{
    //Some code
}
catch (Exception e)
{
    throw;
}

C'est ainsi que je peux avoir un point d'arrêt dans l'attrape, qui a un objet d'exception instancié. Je le fais beaucoup en développant / déboguant. Bien sûr, le compilateur me donne un avertissement sur tous les e inutilisés et, idéalement, ils doivent être supprimés avant la publication de la version.

Ils sont gentils pendant le débogage.


12
2017-09-18 09:50



Une raison valable pour renvoyer des exceptions peut être que vous souhaitez ajouter des informations à l'exception, ou peut-être envelopper l'exception d'origine dans l'une de vos propres créations:

public static string SerializeDTO(DTO dto) {
  try {
      XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
      StringWriter sWriter = new StringWriter();
      xmlSer.Serialize(sWriter, dto);
      return sWriter.ToString();
  }
  catch(Exception ex) {
    string message = 
      String.Format("Something went wrong serializing DTO {0}", DTO);
    throw new MyLibraryException(message, ex);
  }
}

10
2018-05-19 08:03



Est-ce pas exactement équivalent à ne pas   gérer les exceptions du tout?

Pas exactement, ce n'est pas pareil. Il réinitialise la pile de l'exception. Bien que je sois d’accord que cela est probablement une erreur, et donc un exemple de mauvais code.


9
2018-05-19 08:11



Vous ne voulez pas lancer ex - car cela perdra la pile d'appels. Voir Gestion des exceptions (MSDN).

Et oui, le try ... catch ne fait rien d'utile (à part perdre la pile des appels - donc c'est pire - à moins que pour une raison quelconque vous ne vouliez pas exposer cette information).


7
2018-05-19 08:02