9 Stimmen

C# Brauche ich TRY/CATCH, um zu werfen?

Wenn alles, was ich tun möchte, ist die Ausnahme eine Ebene höher zu werfen, wenn es auftritt?

private void TryCatch()
{
   try
   {
       foo();
   }
   catch (Exception ex)
   {
       throw;
   }
}

private void NoTryCatch()
{
   foo();
}

Sind diese beiden Methoden nicht identisch?

Wenn eine Ausnahme in TryCatch auftritt, wird sie eine Stufe höher geworfen, und wenn eine Ausnahme in NoTryCatch auftritt, wird die Ausnahme ebenfalls eine Stufe höher geworfen.

Diese Frage kam auf, nachdem ich ReSharper verwendet und festgestellt hatte, dass es vorschlug, den try/catch-Block zu entfernen, da er überflüssig war.

19voto

Jon Skeet Punkte 1325502

Ja, diese Methoden sind so ziemlich (*) die gleichen. Der einzige Unterschied ist, dass man bei der ersten Methode leicht einen Haltepunkt setzen kann. Ich würde mich immer für die zweite entscheiden, es sei denn, ich muss dort und nur dort unterbrechen (im Gegensatz zu sofortigen Ausnahmen dieses Typs, was einfach wäre). Selbst wenn ich jemals die erste Form verwenden würde, würde ich sie in die zweite Form zurücksetzen, bevor ich den Code festlege.

(*) Es kann durchaus Unterschiede in der Art und Weise geben, wie der JIT sie behandelt. Die erste Variante wird mehr AWL enthalten, was sich auf die Möglichkeiten des Inlinings usw. auswirkt.

EDIT: Ich kann nicht widerstehen, ein bisschen Micro-Benchmarking. Es sieht aus wie try/catch/throw hat böser Auswirkungen auf die Leistung als nur deaktivieren Inlining:

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

public class Test
{
    const int Iterations = 1000000000;

    static void Main()
    {
        Stopwatch sw;

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            SimpleMethod();
        }
        sw.Stop();
        Console.WriteLine("Simple method: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            NoInlining();
        }
        sw.Stop();
        Console.WriteLine("No inlining: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            TryCatchThrow();
        }
        sw.Stop();
        Console.WriteLine("try/catch/throw: {0}", sw.ElapsedMilliseconds);
    }

    static void SimpleMethod()
    {
        Foo();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    static void NoInlining()
    {
    }

    static void TryCatchThrow()
    {
        try
        {
            Foo();
        }
        catch (Exception)
        {
            throw;
        }
    }

    static void Foo() {}
}

Kompilieren mit /o+ /debug-

Ergebnisse (drei Durchläufe):

Einfache Methode: 504, 495, 489
Kein Inlining: 2977, 3060, 3019
try/catch/throw: 5274, 4543, 5145

0 Stimmen

Das war auch meine Vermutung, aber ich hatte nicht die Energie für Nachforschungen. Nicht, dass es etwas zu stoppen, die JIT zu bemerken, dass die Try/Catch in diesem Fall überflüssig ist, ich vermute, und strippen es...

0 Stimmen

Ich kann keine Beweise für meine Behauptung finden. Ich glaube, es war entweder throwing oder try/catch verhindert inline. Ich vermute, es kann tatsächlich werfen vs. fangen sein.

0 Stimmen

Üblere Auswirkungen? (5274-504)/1000000000 = keine Auswirkungen, wenn Sie in foo() etwas tun

3voto

ine Punkte 13823

Nein, Sie brauchen den Try-Catch nicht. Der einzige Grund, warum Sie die erste Funktion verwenden sollten, ist, wenn Sie eine Protokollierung durchführen oder Ressourcen freigeben möchten, bevor Sie die Funktion weiter oben bearbeiten.

1voto

Otávio Décio Punkte 72052

Diese beiden Methoden sind im Wesentlichen identisch. In diesem Fall war ReSharper mit seinem Vorschlag richtig.

1voto

Schmuli Punkte 733

Ich habe darüber nachgedacht, war mir aber nicht zu 100 % sicher, also habe ich nachgesehen. Ich hatte Recht, manchmal.

Wenn Sie die Ausnahme erneut auslösen, was in Ihrem Code der Fall ist, kann es passieren, dass Sie den Stack-Trace ändern. Zunächst einmal, wenn Sie schreiben würden throw ex; die den Stack-Trace zurücksetzen würde. Zweitens, selbst beim Schreiben von throw; es kann auch Fälle geben, in denen Informationen fehlen. Siehe dies Artikel und einige Benutzerkommentare die Weiterverfolgung der Angelegenheit.

Natürlich sind die meisten dieser Probleme im Zusammenhang mit der Stack-Trace und Zeile-Nummern, die wichtig sind, aber ich dachte, es würde auch die Leistung beeinträchtigen, nicht nur wegen der Inlining (oder das Fehlen davon), sondern auch wegen der ganzen Ausnahme fangen und werfen Overhead, aber ich habe nichts Konkretes zu diesem gefunden.

1voto

ewalshe Punkte 3664

Sie sind wirklich nicht dasselbe. Throw selbständig oder throw ex bringen die Stack-Trace-Informationen durcheinander und können die Fehlersuche erschweren.

Der beste Grund, eine Ausnahme abzufangen, ist, dem Stack-Trace einen Kontext hinzuzufügen, z. B:

try {
  Foo();
}
catch (Exception e) {
  throw new BetterException("I did something slightly silly", e);
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X