2009-06-25 10 views
5

Ich habe zwei Funktionen, die unterschiedlich genug Logik haben, aber so ziemlich die gleiche Ausnahmebehandlung:Was ist die beste Möglichkeit, die Ausnahmebehandlungslogik in C# erneut zu verwenden?

public void DoIt1 // DoIt2 has different logic but same exception handling 
{ 
    try 
     ... DoIt1 logic 
    catch (MySpecialException myEx) 
    { 
     Debug.WriteLine(myEx.MyErrorString); 
     throw; 
    } 
    catch (Exception e) 
    { 
     Debug.WriteLine(e.ToString()); 
     throw; 
    } 
} 

Es ist nicht möglich, einen einzigen Eintrittspunkt für DoIt1 und DoIt2 zu verwenden, da sie von außen aufgerufen werden. Ist Copy/Pase (für den Ausnahmeblock) der beste Ansatz?

Antwort

6

Es hängt davon ab ... wenn es , die viel Gemeinsamkeit, die Sie in der , was zu tun als Parameter übergeben konnte - entweder als eine Schnittstelle oder ein Delegierter:

void Foo(Action thingToDo) { 
    if(thingToDo == null) throw new ArgumentNullException("thingToDo"); 
    try { 
     thingToDo(); 
    } catch {...} // lots of 
} 

Und nennen als :

Foo(delegate { /* logic A */ }); 

Foo(delegate { /* logic B */ }); 
5

Versuchen:

public static class Catching<TException> where TException : Exception 
{ 
    public static bool Try<T>(Func<T> func, out T result) 
    { 
     try 
     { 
      result = func(); 
      return true; 
     } 
     catch (TException x) 
     { 
      // log exception message (with call stacks 
      // and all InnerExceptions) 
     } 

     result = default(T); 
     return false; 
    } 

    public static T Try<T>(Func<T> func, T defaultValue) 
    { 
     T result; 
     if (Try(func, out result)) 
      return result; 

     return defaultValue; 
    } 
} 

Beispiel:

int queueSize = Catching<MyParsingException> 
    .Try(() => Parse(optionStr, "QueueSize"), 5); 

Wenn Parse wirft ein MyParsingException, queueSize zu 5 ausfällt, andernfalls wird der Rückgabewert von Parse verwendet wird (oder eine andere Ausnahme normalerweise propagieren , was normalerweise mit einer unerwarteten Ausnahme gewünscht ist).

Dadurch wird verhindert, dass der Codefluss unterbrochen wird, und die Protokollierungsrichtlinien werden zentralisiert.

Sie können spezielle Versionen dieser Art von Ausnahmeverpackung für spezielle Fälle, z. einen bestimmten Satz von drei Ausnahmen oder was auch immer fangen.

0

könnten Sie haben so etwas wie:

public static class ErrorHandler 
{ 

    public static void HandleMyException(MyException myEx) 
    { 
     Debug.WriteLine(myEx.MyErrorString); 
     throw; 
    } 

    public static void HandleException(Exception myEx) 
    { 
     Debug.WriteLine(e.ToString()); 
     throw; 
    } 

} 

oder, in diesem speziellen Fall haben eine generische Funktion wie:

public static class ErrorHandler 
{ 

    public static void WriteAndThrow(string msg) 
    { 
     Debug.WriteLine(msg); 
     throw; 
    } 

} 
+0

Überladungen machen in der Laufzeit nichts, und es ist genau das, was in jedem DoIt vermieden werden muss. –

2

Für äußerstes Ende des Spektrums möglicher Lösungen finden Sie im Aspect-Oriented-Programmiertechniken und Tool wie PostSharp oder Microsoft Policy Injection Block. Auf diese Weise können Sie einen Aspekt definieren, der etwas an der Exception und weben es in alle Stellen in Ihrem Code, die es brauchen.

1

Wenn Sie nur die Nachrichten und Elemente der Ausnahmen protokollieren möchten, ohne eine spezielle Verarbeitung im catch-Block durchzuführen, können Sie eine Reflection-basierte Objektprotokollfunktion erstellen und die Exception als Argument übergeben. Auf diese Weise haben Sie nicht viele Catch-Blöcke.

Und wenn Sie der Besitzer des Codes sind, können Sie die Protokollierungsprozedur in den MySpecialException-Konstruktor einfügen, den Catch-Block entfernen und den Code sauberer machen.

Verwandte Themen