Frage

Edit: Ich habe an den Antworten Code sehe: NONE von ihnen tun, was ich will (ich habe überprüft). Es scheint, dass es keine Möglichkeit gibt, zu tun, was ich in nativen C # soll. Ich denke, das ist keine Katastrophe nur schade, da .NET es nicht unterstützt (siehe akzeptierte Antwort).

Danke alle.


Ich habe c # -Code (Teil eines Testrahmens, die mit Ausnahme nie unter einem Debugger ausgeführt werden), wie diese, die es zeigen tatsächlich die Ausnahme abfangen zu vermeiden, dass der Code in dem abgewickelten Teil des Stapels macht das Debuggen einen königlicher Schmerz .

Bool bad = true;
try
{
   MightThrow();
   bad = false;
}
finally
{
   if(bad) DoSomeLoggingOnFailure();

   //// Does not catch!!!! 
   //// exception continues to unwind stack.

   //// Note that re throwing the exception is NOT
   //// the same as not catching it in the first place
}

ist sie ein besserer Weg, dies zu tun?

  

Eine Lösung würde genau in Bezug auf un-gefangen Ausnahmen unter dem Debugger, so verhalten hat. Es müßte in der nur einer ersten Chance führen und der Debugger an dem Punkt zu brechen, dass die Ausnahme war ursprünglich geworfen, nicht in einem catch-Block.

     

Im Einzelnen muß er den Debugger auf un-gefangen Ausnahmen ein in Seiten MightThrow zu stoppen.

Die folgende funktioniert nicht, weil es die Debugger Pause an der richtigen Stelle

hat versagt
try { ... } catch { throw; }

Und dies nicht funktioniert, weil es stapeln info verliert (und bricht auch an der falschen Stelle).

try { ... } catch(Excption e) { throw e; }

ich gewusst, dass in D ich eine scope(failure) Block

War es hilfreich?

Lösung

Also, in .NET, was Sie fragen, ist theoretisch möglich, aber es wird nicht einfach sein.

CIL eigentlich definiert fünf Arten von Ausnahmebehandlung Block! Die try, catch und finally diejenigen, die Sie in C # gewohnt sind, und zwei andere:

  • filter - ähnlich wie bei einem catch Block, sondern kann beliebigen Code ausgeführt werden, um zu bestimmen, ob sie will den Fehler behandeln, anstatt nur auf Typen entsprechen. Dieser Block hat Zugriff auf das Ausnahmeobjekt, und hat die gleiche Wirkung auf dem Ausnahme-Stack-Trace als catch Block.

  • fault - ähnlich wie bei einem finally Block, aber es wird nur dann ausgeführt, wenn eine Ausnahme auftritt. Dieser Block keinen Zugriff auf das Ausnahmeobjekt hat, und hat keinen Einfluss auf dem Ausnahme-Stack-Trace (wie ein finally Block).

filter ist in einigen .NET-Sprachen (zum Beispiel VB.NET, C ++ / CLI) zur Verfügung, sondern in C # nicht vorhanden, leider. Allerdings weiß ich nicht, jede Sprache, andere als CIL, dass der fault Block ausgedrückt werden kann.

Weil es können in IL getan werden, bedeutet nicht alles verloren ist, though. In der Theorie Reflection.Emit verwenden Sie könnten dynamisch eine Funktion zu emittieren, der einen fault Block hat und dann den Code übergeben Sie als Lambda-Ausdrücke zulaufen möchten (dh eine für den Versuch Teil, eine für den Fehlerteil, und so weiter), jedoch (a) ist dies nicht einfach ist, und (b) ich bin nicht überzeugt, dass dies werden Ihnen tatsächlich einen nützlichere Stack-Trace geben, als Sie zur Zeit zu bekommen.

Leider ist die Antwort kein „hier ist, wie es zu tun“ Art Sache, aber zumindest jetzt wissen Sie! Was Sie tun, jetzt ist wahrscheinlich der beste Ansatz IMHO.


Hinweis zu denen sagen, dass der Ansatz in der Frage verwendet ‚schlechte Praxis‘ ist, ist es wirklich nicht. Wenn Sie einen catch Block implementieren Sie sagen „Ich brauche etwas mit der Ausnahme-Objekt zu tun, wenn eine Ausnahme auftritt“, und wenn Sie eine finally implementieren Sie sagen: „Ich brauche nicht das Ausnahmeobjekt, aber ich brauche zu tun etwas vor dem Ende der Funktion“.

Wenn das, was Sie tatsächlich versucht zu sagen, ist „Ich habe nicht das Ausnahmeobjekt brauchen, aber ich brauche etwas zu tun, wenn eine Ausnahme auftritt“, dann sind Sie auf halbem Weg zwischen den beiden, dh Sie einen fault Block wollen . Da dies nicht in C # ist, haben Sie nicht eine ideale Option, so können Sie die Option auch wählen, die weniger wahrscheinlich ist, Fehler verursachen, indem sie erneut zu werfen zu vergessen, und welche nicht korrupt den Stack-Trace.

Andere Tipps

Wie wäre es damit:

try
{
  MightThrow();
}
catch
{
  DoSomethingOnFailure();
  throw; // added based on new information in the original question
}

Wirklich, das ist alles, was Sie getan haben. Schließlich ist für Dinge, die unabhängig davon, ausgeführt werden muss, ob eine Ausnahme aufgetreten.

[ Bearbeiten Klarstellung]

Auf der Grundlage der Kommentare, die Sie erwähnen habe, möchten Sie die Ausnahme geworfen fortzusetzen, ohne seinen ursprünglichen Stack-Trace zu modifizieren. In diesem Fall sollten Sie den schmucklos Wurf verwenden, die ich hinzugefügt haben. Dies ermöglicht die Ausnahme den Stapel fortzusetzen und immer noch erlauben Sie einen Teil der Ausnahme zu behandeln. Typische Fälle könnte es sein, Netzwerkverbindungen oder Dateien zu schließen.

[ Zweite bearbeiten: In Bezug auf Ihre Klarstellung]

  

Im Einzelnen muss ich den Debugger auf   un-gefangen Ausnahmen bei der stoppen   Ausgangspunkt des Wurfes (in   MightThrow) nicht im catch-Block.

Ich würde behaupten, gegen je eine Best-Practice zu brechen (und ja, das ist eine Best-Practice für Ausnahmen teilweise Handling) einigen kleineren Wert Ihrer Debuggen hinzuzufügen. Sie können ganz einfach die Ausnahme überprüfen Sie die Position der Ausnahme throw zu bestimmen.

[ Endgültiger edit: Sie haben Ihre Antwort]

kronoz hat Sie nachdenklich zur Verfügung gestellt mit der Antwort gesucht Sie. Nicht beste Praktiken brechen - richtig Visual Studio verwenden! Sie können Visual Studio zu brechen genau festgelegt, wenn eine Ausnahme ausgelöst wird. Hier offizielle Informationen über das Thema .

war ich eigentlich nichts von der Funktion, so gehen Sie gibt ihm die akzeptierte Antwort. Aber bitte, gehen Sie nicht versuchen, Ausnahmen in einigen flippige Art und Weise zu handhaben nur sich selbst eine Hand Debuggen zu geben. Alles, was Sie tun, öffnen sich mehr Fehler auf.

Wenn Sie interessiert sind in den Debugger einfach genau zu stoppen, wo die Ausnahme dann aufgetreten haben Sie aus erster Chance Ausnahmen in Betracht gezogen?

Wenn Sie unter Extras |. Ausnahmen dann die Common Language Runtime Exceptions Feld ankreuzen, der Debugger an der Stelle der Ausnahme stoppt unabhängig von irgendwelchen try / catch / finally Blöcke

Aktualisieren : Sie können die genaue Ausnahme geben Sie durch die Erweiterung des [+] Baum im Dialogfeld Ausnahmen fangen wollen. Obwohl natürlich wird es jedes Mal Feuer jeder Ausnahme des angegebenen Typs [s] auftritt [s], können Sie es auf und ab nach Belieben auch in der Mitte einer Debug-Sitzung wechseln, so mit umsichtigem Verwendung von Breakpoints können Sie es Ihr Bieten zu tun. Ich benutzte es erfolgreich um die zu bekommen verwenden Reflexion Ball Schmerz ‚Ziel eines Aufrufs hat eine Ausnahme ausgelöst‘ Ursprungs Objekte zu instanziiert. Sehr nützliches Werkzeug in einem solchen Fall. Auch die Einheimischen beachten und Stack-Trace sollte fest, wie weit verfügbar sein, wie ich mich erinnere (nur habe einen schnellen Test und sie sind verfügbar), so dass keine Probleme gibt.

Natürlich, wenn Sie wollen die Dinge protokollieren dann, dass außerhalb des Bereichs eines IDE-Debugger ist; und in dem Fall der ersten Chance Ausnahmen werden dir nicht helfen!

Geben Sie ihm gehen zumindest, Ich fand sie sehr nützlich, und sie könnten besser geeignet für Ihr Problem sein, als Sie denken.

Was ist los mit:

try
{
   MightThrow();
}
catch
{
   DoSomthingOnFailure();
   throw;
}

Für Code, der nur auf Ausnahmen ausgeführt werden soll, verwenden Sie den catch-Block:

try
{
   MightThrow();
}
catch (Exception ex)
{
   // this runs only when there was an exception
   DoSomthingOnFailure();
   // pass exception on to caller
   throw; 
}
finally
{
   // this runs everytime
   Cleanup();
}

Dies ist, was Sie wollen. Es wird nur diese Methode aufrufen, wenn ein Fehler auftritt, und die „werfen“ Anweisung die Ausnahme mit der Aufrufliste intakt erneut werfen.

try
{
   MightThrow();
}
catch
{
   DoSomthingOnFailure();
   throw;
}

Ein „endlich“ Block, der nur bei einem Fehler ausgeführt wird, wird „fangen“ genannt (ohne Parameter). : -)

Jetzt gibt es eine kleine Einschränkung. Wenn Sie für einen bestimmten Ausnahmetyp eine spezielle „fangen“ haben, falls und haben eine generische „fangen“, die für alle Ausnahmen funktioniert, werden Sie ein bisschen eine eigene Logik zu tun haben.

So würde ich so etwas wie:

  try
  {
    MightThrow();
  }
  catch(MyException ex)
  {
    // Runs on MyException
    MySpecificFailureHandler()
    // Since we have handled the exception and can't execute the generic
    // "catch" block below, we need to explicitly run the generic failure handler
    MyGenericFailureHandler()
  }
  catch
  {
    // Runs on any exception hot handled specifically before
    MyGenericFailureHandler()
    // If you want to mimic "finally" behavior and propagate the exception
    // up the call stack
    throw;
  }
  finally
  {
    // Runs on any failure or success
    MyGenericCleanupHandler();
  }

Jedes Beispiel so weit ist die ursprüngliche Stacktrace nach meinen Tests zu verlieren. Hier ist eine Lösung, die für Sie arbeiten soll.

private static void PreserveStackTrace(Exception exception)
{
  MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
    BindingFlags.Instance | BindingFlags.NonPublic);
  preserveStackTrace.Invoke(exception, null);
}

try
{
   MightThrow();
}
catch (Exception ex)
{
    DoSomethingOnFailure();
    PreserveStackTrace(ex);
    throw;
}

Wie wäre es nur eine Ausnahme zu kontrollieren, dass "MightThrow" hat nicht werfen?

Bool bad = true;
try
{
   MightThrow();
   bad = false;
}
catch (SomePrivateMadeUpException foo)
{ 
   //empty
}
finally
{
   if(bad) DoSomeLoggingOnFailure();   
}

Lassen Sie mich Ihre Anforderungen an die Art und Weise rekapitulieren ich sie verstehe:

  1. Sie wollen einige Code, der nur dann ausgeführt wird, wenn eine Ausnahme erzeugt wird, um einige Protokollierung zu tun.
  2. Sie möchten Ihr Test-Framework unter Debugger und brechen an der Stelle laufen, in dem die Ausnahme ausgelöst wird.

Um Ihre erste Anforderung zu erfüllen, sollten Sie den Code so, wie jeder vorgeschlagen schreiben -. Parameterlos fängt mit und werfen

Ihre zweite Anforderung gerecht zu werden, während des parameterlos Fang verwenden, können Sie Ihren Debugger konfigurieren zu brechen, wenn eine Ausnahme ist, nicht nur, wenn es eine nicht behandelte Ausnahme. Ich vermute, Sie wissen, wie es zu tun, aber ich werde es hier der Vollständigkeit halber für Antwort setzen. In VS können Sie tun, dass in Debug -> Ausnahme -> Common Language Runtime Ausnahmen -> überprüfen Sie die Thrown Checkbox

Wenn Sie wissen, dass Ihre App eine Menge behandelt Ausnahmen auslöst, dass möglicherweise keine Option für Sie sein. An diesem Punkt links die einzige Wahl Ihre erste Anforderung zu erfüllen ist, um entweder der Code schreiben, für die Ausnahmeprotokollierung Zwecke zu verwenden schließlich oder schaut in die direkten IL emittierende Route als Greg Buche schlägt.

Ob jedoch die schließlich Code ausgeführt wird, hängt von der Debugger Sie verwenden. Insbesondere bricht VS auf einer unhadled Ausnahme vor dem schließlich ausgeführt wird, und lassen Sie nicht weiter. So, wenn Sie aus dem Prozess an diesem Punkt trennen, wird Ihr Logging-Code nie ausgeführt werden. Mit anderen Worten, stört die zweite Anforderung mit der Erfüllung der ersten Anforderung.

Sie können Ihre Logik in einer benutzerdefinierten Klasse kapseln, so etwas wie:

    public  class Executor
{
    private readonly Action mainActionDelegate;
    private readonly Action onFaultDelegate;

    public Executor(Action mainAction, Action onFault)
    {
        mainActionDelegate = mainAction;
        onFaultDelegate = onFault;
    }

    public  void Run()
    {
        bool bad = true;
        try
        {
            mainActionDelegate();
            bad = false;
        }
        finally
        {
            if(bad)
            {
                onFaultDelegate();
            }
        }
    }

}

Und verwenden Sie es als:

            new Executor(MightThrow, DoSomeLoggingOnFailure).Run();

Hope, das hilft.

Ist das nicht das gleiche wie:

try 
{
    MightThrow();
}
catch (Exception e) 
{
    DoSomethingOnFailure();
    throw e;
}

könnten Sie schreiben, oder jemand für Sie, eine kleine Montage in VB.net schreiben, die eine TryFaultCatchFinally implementiert (T) -Methode, die vier Delegierten akzeptiert:

  1. TryMethod - Eine Aktion (von T), um den "Try" Block durchzuführen.
  2. FaultMethod - A Predicate (Of T, Exception), die, wenn eine Ausnahme auftritt, wird aufgerufen, vor any "endlich" Blöcke laufen; wenn es wahr zurückgibt wird der Catch-Block laufen - sonst wird es nicht.
  3. CatchMethod - Eine Aktion (T, Exception) zu erfolgen, wenn eine Ausnahme aufgetreten war und FaultMethod zurück true; geschieht nach dem „endlich“ Blöcke laufen.
  4. FinallyMethod - Eine Aktion (OF T, Exception, Boolean) als "Finally" Block durchgeführt werden. Die übergebene in Ausnahme wird null sein, wenn TryMethod bis zur Fertigstellung läuft, oder wird die Ausnahme halten, die es verursacht zu verlassen. Die Boolesche wird richtig sein, wenn die Ausnahme gefangen wurde, oder andernfalls false.

Beachten Sie, dass, wenn die FaultMethod ausgeführt wird, kann man in der Lage sein, den Zustand der Objekte zu untersuchen, die die Ausnahme verursacht, vor einem solchen Zustand durch Schließlich Blöcke zerstört wird. Man muss eine gewisse Sorgfalt verwenden, wenn dies zu tun (alle Sperren, die gehalten wurden, als die Ausnahme ausgelöst wurde, werden weiterhin gehalten werden), aber die Fähigkeit, kann immer noch manchmal nützlich sein, vor allem bei der Fehlersuche.

Ich würde vorschlagen, dass die Routine Blick etwas wie:

    Shared Sub TryFaultCatchFinally(Of T)(ByVal TryProc As Action(Of T), _
                                          ByVal FaultProc As Func(Of T, Exception, Boolean), _
                                          ByVal CatchProc As Action(Of T, Exception), _
                                          ByVal FinallyProc As Action(Of T, Exception, Boolean), _
                                          ByVal Value As T)
        Dim theException As Exception = Nothing
        Dim exceptionCaught As Boolean = False
        Try
            TryProc(Value)
            theException = Nothing
            exceptionCaught = False
        Catch Ex As Exception When CopyExceptionAndReturnFalse(Ex, theException) OrElse FaultProc(Value, Ex)
            exceptionCaught = True
            CatchProc(Value, Ex)
        Finally
            FinallyProc(Value, theException, exceptionCaught)
        End Try
    End Sub

Nein, ich denke, das ein gemeinsames Idiom ist die Art und Weise haben Sie es.

EDIT Um klar zu sein, bieten die „fängt“ und dann „rethrow“ Strategien, um die gleiche Laufzeit Semantik, aber sie die Erfahrung ändern, wenn der VS-Debugger angeschlossen ist. Tooling und Wartung ist wichtig; Debuggen erfordert, dass Sie oft zu ‚alle ersten Chance Ausnahmen zu fangen‘, und wenn Sie mit vielen ‚falschen‘ ersten Chance Ausnahmen am Ende aufgrund catch-then-rethrow in Ihrem Code, es tut weh wirklich die Fähigkeit, den Code zu debuggen. Dieses Idiom ist über gut mit den Werkzeugen interagieren, sowie klar die Absicht zum Ausdruck (Sie wollen nicht zu ‚fangen‘, entscheiden nicht umgehen kann, und rethrow, statt Sie nur wollen, melden Sie sich, dass eine Ausnahme ist das passiert aber lassen es weitergeben by).

Haben Sie darüber nachgedacht, mit Attribute der DebuggerStepThrough? http://msdn.microsoft.com/en-us/library /system.diagnostics.debuggerstepthroughattribute.aspx

[DebuggerStepThrough]
internal void MyHelper(Action someCallback)
{
    try
    {
        someCallback();
    }
    catch(Exception ex)
    {
        // Debugger will not break here
        // because of the DebuggerStepThrough attribute
        DoSomething(ex);
        throw;
    }
}
try
{
   MightThrow();
}
catch
{
   DoSomethingOnFailure();
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top