Dans .NET, y a-t-il un avantage à essayer / attraper lorsque le piège ne fait que rediffuser

StackOverflow https://stackoverflow.com/questions/1207172

  •  05-07-2019
  •  | 
  •  

Question

  

Double possible:
   Pourquoi intercepter et rediffuser une exception en C #?

Je rencontre parfois un code C # qui ressemble à ceci:

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

Je comprends qu'il est possible de faire quelque chose comme consigner le message d'exception, puis le relancer. Je parle d'une capture qui ne fait que renvoyer l'exception. Je ne vois pas pourquoi. J'ai trois questions:

1) Y a-t-il un avantage à cela

2) Cela ralentit-il le code du tout

3) Est-ce que cela ferait une différence si le bloc de capture était comme suit:

        catch (Exception)
        {
            throw;
        }
Était-ce utile?

La solution

Ceci rejoue la même exception exacte :

    catch (Exception)
    {
        throw;
    }

Alors que ceci retrousse l'exception sans la trace de pile d'origine:

    catch (Exception e)
    {
        throw e;
    }

Il y a souvent une bonne raison pour jeter; , car vous pouvez enregistrer l'exception ou faire autre chose avant de la renvoyer à nouveau. Je ne suis au courant d'aucune bonne raison pour jeter e; , car vous allez effacer les précieuses informations de trace de la pile.

Autres conseils

Pas si vous ne faites rien d'autre dans la capture ... Mais ceci est souvent utilisé pour faire d'autres choses dans la capture, telles que la journalisation, ou d'autres types de traitement d'exception, avant de la renvoyer.

J'utilise cette technique pour pouvoir placer un point d'arrêt lors du débogage. Parfois, je le retire une fois que j'ai terminé ...

La principale différence est que la trace de pile de l'exception sera modifiée pour indiquer qu'elle provient de l'emplacement de try-catch dans le premier exemple.

Le deuxième exemple conserve la trace de la pile.

Existe-t-il un avantage

D'une manière générale non. Tout ce que ce modèle fera est de réinitialiser la trace de pile au point du nouveau lancer. Cela rendra simplement plus difficile pour les développeurs la recherche de la source du problème

Est-ce que cela ralentit le code du tout

Du tout? Peut-être. Ralentir par une différence mesurable? Non.

Cela ferait-il une différence si le blocage était le suivant?

Oui, cette capture est essentiellement redondante. Il renverra l'exception qui conservera la trace de pile d'origine et n'aura aucun impact perceptible sur votre application.

1 - Je ne vois aucun avantage du tout. Si vous ne gérez pas l'exception, laissez l'essai / rattraper. L’autre problème de cet exemple est que vous ne lancez pas l’exception réelle, mais une nouvelle.

2 - oui - mais à moins que ce ne soit une grosse boucle de code répété, vous ne remarquerez probablement pas de différence.

3 - Oui. Dans le premier exemple, vous manipulez votre pile d'appels. Cet exemple conserve la pile intacte en faisant bouillonner l'exception au lieu d'en lancer une nouvelle.

Si vous ne faites vraiment rien d'autre, je n'ai jamais trouvé qu'un seul avantage: vous pouvez placer un point d'arrêt sur la ligne throw . Cela le rend très spécifique (plutôt que de simplement rompre à chaque fois que ce type d'exception est levé).

Je ne le ferais que pendant le débogage, puis je reviendrais avec le code.

J'ai rédigé un test rapide pour montrer les différences. Voici le code de test:

try
{
    var broken = int.Parse("null");
}
catch (Exception ex1)
{
    System.Diagnostics.Trace.WriteLine(ex1.ToString());
}

try
{
    try
    {
        var broken = int.Parse("null");
    }
    catch (Exception)
    {
        throw;
    }
}
catch (Exception ex2)
{
    System.Diagnostics.Trace.WriteLine(ex2.ToString());
}

try
{
    try
    {
        var broken = int.Parse("null");
    }
    catch (Exception ex3)
    {
        throw ex3;
    }
}
catch (Exception ex4)
{
    System.Diagnostics.Trace.WriteLine(ex4.ToString());
}

En cours d'exécution, j'obtiens le résultat suivant:

A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Int32.Parse(String s)
   at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 18
A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
A first chance exception of type 'System.FormatException' occurred in QuickTests.exe
System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Int32.Parse(String s)
   at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 33
A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
A first chance exception of type 'System.FormatException' occurred in QuickTests.exe
System.FormatException: Input string was not in a correct format.
   at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 49

Vous remarquerez que les deux premières exceptions fonctionnent de la même manière. Donc, "jeter;" ne change rien en ce qui concerne l'exception qui remonte la pile. Cependant "jeter ex3;" fait en sorte que l'exception signalée soit différente, en modifiant le suivi de pile pour l'exception.

C'est souvent bien pour la journalisation. De même, si vous omettez l'argument dans la nouvelle lecture, cela ne modifie pas la trace de pile de e.

Parfois, vous souhaitez autoriser certains types, par exemple. voici un traitement spécial pour tout sauf FooException:

try
{
    // ...
}
catch (FooException)
{
    throw;
}
catch (Exception ex)
{
    // handle differently, like wrap with a FooException
    throw new FooException("I pitty the Foo.", ex);
}

Bien sûr.

La plupart du temps, vous souhaitez enregistrer l'exception avant de la lancer et éventuellement enregistrer certaines valeurs de variable issues de la méthode.

Le prendre pour le lancer ne vous rapporte toutefois pas beaucoup.

Juste comme ça, non. Cependant, vous voudrez peut-être faire ceci:

catch (Exception ex)
{
     LogException(ex);
     throw;
}

Où LogException () est une classe personnalisée qui, erm, enregistre l'exception ou envoie une alerte par courrier électronique ou quelque chose d'autre.

Je pense que le but est de s’assurer qu’un seul TYPE d’exception est levé. C'est un très mauvais anti-motif IMHO

par exemple

try
{
    throw XYZ();
}
catch(Exception e)
{
    throw e;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top