Elegantes fangen mehrere Exceptions mit gleicher behandlung



  • Ich habe eine Funktion die mehrere Exceptiontypen werfen kann. Ich möchte nun bei einem Auftreten von 3 bestimmten Exceptiontypen jeweils das gleiche fehlerverhalten machen. Aber irgendwie frage ich mich, ob das nicht auch eleganter geht also so:

    try
    {
      callFuncWithException();
    }
    catch(ExceptionType1 ex)
    {
       ErrHand();
    }
    catch(ExceptionType2 ex)
    {
       ErrHand();
    }
    catch(ExceptionType3 ex)
    {
      ErrHand();
    }
    

    Alternative wäre ja auf System.Exception zu regieren, mit typeof zu prüfen und notfalls zu rethrowen. Aber irgendwie wirkt das auch nicht sondernlich schön, da ist mir der erste Weg noch lieber. Gibts noch alternativen?
    Achja, ich muss noch sagen die Exceptions habe ich nicht in der Hand, ich kann also nicht die drei Exception von einer übergeordneten Ableiten und diese dann Fangen.


  • Administrator

    http://stackoverflow.com/questions/791390/more-elegant-exception-handling-than-multiple-catch-blocks
    http://stackoverflow.com/questions/136035/catch-multiple-exceptions-at-once
    http://blogs.msdn.com/b/toub/archive/2004/03/05/84698.aspx

    Oder zusammengefasst:
    Es gibt verschiedene Möglichkeiten, aber keine ist das Gelbe vom Ei. Ich würde so verbleiben, wie du es jetzt gelöst hast. So schlimm sieht das noch gar nicht aus. Ich habe ein C++/CLI Projekt, wo auf 6 Exceptiontypen fast gleich reagiert wird. Um es ein wenig zu verschönern, habe ich das Ganze in eine Funktion ausgelagert, welche nur für das Fangen der Exceptions zuständig ist 🙂
    Also dann ca. sowas:

    // ... code ...
    
    TryCallFuncWithException();
    
    // ... code ..
    
    int TryCallFuncWithException()
    {
      try
      {
        return CallFuncWithException();
      }
      catch(A a)
      {
        // ...
      }
      catch(B b)
      {
        // ...
      }
      // usw.
      catch(...)
      {
        // ...
      }
    
      return 0;
    }
    

    So wird der Lesefluss im normalen Code nicht sonderlich gestört.

    Grüssli



  • Wenn der Handler immer das selbe tut:

    try
    {
       ...
    }
    catch
    {
        HandleException();
    }
    
    // ---
    
    void HandleException()
    {
        try
        {
            throw;
        }
        catch (Type1 e1)
        {
            HandleE1();
        }
        catch (Type2 e2)
        {
            HandleE2();
        }
        catch (Type3 e3)
        {
            HandleE3();
        }
        // andere Typen fangen wir nicht, dadurch fliegen die aus unserem Handler wieder raus,
        // und weiter aus dem catch block wo die Exception das erste mal gefangen wurde
    }
    

    Wenn er nicht immer dasselbe tut kann man noch delegates mitgeben oder was auch immer.

    Ist im Prinzip ähnlich wie die Variante von Dravere, nur sozusagen "auf links gedreht".


  • Administrator

    @hustbaer,
    1. Wie im verlinkten Blogeintrag erklärt, kann dein Vorhaben Nachteile aufweisen, weil Exceptions, welche durchfliegen, nicht mehr korrekt zurückverfolgt werden können, wo sie tatsächlich aufgetreten sind. Es ist möglich, dass man nur zurück bis zum rethrow Statement kommt.
    2. In C# ist das gar nicht erlaubt. Der Kompiler wird über einen CS0156 meckern. 😉

    Grüssli



  • Uff, ja, ich fürchte was du sagst macht Sinn 🙂

    Sorry für Unsinns-Verbreitung.

    Dass C# das re-throw nicht wie C++ unterstützt wusste ich nicht, aber man könnte ja immer noch "object" fangen und dann weiterwerfen. Oder gilt die Beschränkung auf "System.Exception" in C# auch für's Fangen?

    Die Frage ist allerdings eh eher akademisch... deine Lösung lässt sich mit delegates ja auch relativ schön einsetzen, also kein Grund die zum Debuggen weniger gute "re-throw" Variante zu verwenden.



  • Der Vollständigkeit halber gäbe es noch folgende Möglichkeit:

    AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(TopLevelErrorHandler);
    
    static void TopLevelErrorHandler(object sender, UnhandledExceptionEventArgs args)
    {
        if (args.ExceptionObject is ExceptionType1 || args.ExceptionObject is ExceptionType1 || args.ExceptionObject is ExceptionType1)
        {
         // do something
        }
    }
    

  • Administrator

    hustbaer schrieb:

    Dass C# das re-throw nicht wie C++ unterstützt wusste ich nicht, aber man könnte ja immer noch "object" fangen und dann weiterwerfen. Oder gilt die Beschränkung auf "System.Exception" in C# auch für's Fangen?

    Nimm die Fehlermeldung von vorhin und subtrahiere 1 davon, dann erhälst du CS0155.
    Allerdings habe ich nicht so recht verstanden, worauf du damit eigentlich hinaus willst.

    @loks,
    Ist die "Lösung" nicht ein kleines bisschen übertrieben?
    Zudem behandelt man dann die Exception nicht dort, wo man möchte. Und das Programm stürtzt danach trotzdem ab, bzw. wird beendet. Ich glaube kaum, dass dies Fedaykin möchte 😉

    Grüssli


Anmelden zum Antworten