2016-07-21 11 views
3

ich im Moment etwas langweilige Muster bin mit Fehlermeldung für den Benutzer zu erzeugen, eine lange Operation ausgeführt wird:Unterbrechung lang Methode Muster läuft

string _problem; 

void SomeLongRunningMethod() 
{ 
    try 
    { 
     _problem = "Method1 had problem"; 
     Method1(); 
     _problem = "Unexpected error during doing something in Method2"; 
     if(Method2()) 
     { 
      _problem = "Method3 fails"; 
      Method3(); 
     } 
     _problem = "Not possible to obtain data"; 
     var somedata = Method4(); 
    } 
    catch(Exception) 
    { 
     MessageBox.Show("Problem with some long running method: " + _problem); 
    } 
} 

Beide Methoden werfen kann, und ich will den Benutzer sagen, an dem Scheitern Schritt tritt ein. Dies geschieht durch Setzen von _problemvor mit einem von ihnen.

In einigen Fällen kann ich verschiedene Exception Arten zu fangen, aber das funktioniert nicht immer, z. sowohl Method1 als auch Method2 können throw InvalidOperationException().

Dieser wiederholte Code sieht wie ein Muster aus. Obwohl ich es nicht erkennen kann. Irgendwelche Ideen? Wie verbessert man die Lesbarkeit?

+0

Ich nehme einfach an, dass das Beispiel übermäßig vereinfacht ist und Sie * * * * erkennen, dass Sie die Ausnahme anzeigen (oder protokollieren) müssen Details (oder Sie haben eine Deb ugging Alptraum, wenn der Kunde anruft und sagt Ihnen "Methode 3 schlägt fehl, was soll ich jetzt tun?"). Abgesehen davon: Sehr gute Frage! – Heinzi

+0

@ Heinzi, ja, das ist ein vereinfachtes Stück, das ich verbessern möchte. Wenn "Methode 3" fehlschlägt, gibt es eine gute * verwandte * Nachricht, z. Wenn es eine Methode ist, welche Abfragedatenbank wird es dem Benutzer sagen: "Datenbankproblem" (es macht keinen Sinn, Benutzerausnahme anzuzeigen, z. B. "NullReferenceException"). Damit kann der Benutzer das melden oder sogar ** versuchen, etwas zu tun (es gibt Datenbank-Service-Menü, um häufige Probleme zu beheben, etc.). Außerdem werden alle Probleme protokolliert, so dass ich genau sehen kann, was auf welcher Linie passiert. – Sinatr

Antwort

4

Sie when im catch verwenden könnte zwischen denselben Ausnahmetypen zu differenzieren und welche Methode zu überprüfen, diese Ausnahme ausgelöst hat:

void SomeLongRunningMethod() 
{ 
    try 
    { 
     Method1(); 
     if (Method2()) 
     { 
      Method3(); 
     } 
     var somedata = Method4(); 
    } 
    catch (InvalidOperationException invEx) when (invEx.TargetSite?.Name == nameof(Method1)) 
    { 
     // ... 
    } 
    catch (InvalidOperationException invEx) when (invEx.TargetSite?.Name == nameof(Method2)) 
    { 
     // ... 
    } 
    catch (Exception ex) 
    { 
     // ... 
    } 
} 
+0

Dies ist eine gute Idee, aber dies unterscheidet nicht den Fall, wenn eine der Methoden zum zweiten Mal aufgerufen wird. Ein Beispiel: 'ReadFile (" file1.txt ")' und irgendwann später 'ReadFile (" file2.txt ")'. Momentan kann ich einen anderen Wert auf "Problem" setzen, z. '_problem = $" Reading {Dateiname} ";'. Irgendeine Idee? Ich verstehe, dass es mein Problem ist, dieses Kriterium in der Frage nicht zu erwähnen (immer noch lernen, Fragen richtig zu stellen .. seufz .. und deine Antwort deckt die aktuelle Frage perfekt ab). – Sinatr

+0

@Sinatr: Entweder alle 'ReadFile' Aufrufe in einen' try-catch' umbrechen oder die Methode ein 'bool' zurückgeben (wenn es momentan' void' ist) oder einen 'out bool success'-Parameter hinzufügen, um festzustellen, ob die Methode funktioniert erfolgreich ausgeführt Dann bleibt der Code einfach und Sie können Ihr Ergebnis/Fehlermeldung aus dem Ergebnis der Booleschen (zB 'bool canReadFile1 = ReadFile (" file1.txt ")') erstellen. –

+0

Ich muss erwähnen, dass Boolesche Erfolgswerte ein Code-Geruch sind, da sie normalerweise detailliertere Fehlerinformationen zerstören (warum * genau * ist die Methode fehlgeschlagen), was das Debugging viel schwieriger macht. Wenn Sie diesen Weg gehen, geben Sie stattdessen eine Zeichenfolge mit einer Fehlermeldung zurück. – Heinzi

2

Sie können die Methode, die die Ausnahme verursacht hat, mit error.TargetSite abrufen. Das einzige, was müssen Sie ist Linie Ihren Fang ändern: catch (Exception error)

1

Ich würde Machen Sie eine Reihenfolge der Dinge, die Sie tun und durchlaufen möchten:

var methodList = new[]{ 
    new{action = (Action)Method1, identifier = "Method1"}, 
    new{action = (Action)Method2, identifier = "Method2"}, 
    new{action = (Action)Method3, identifier = "Method3"}, 
}; 
string problem = null; 
foreach(var info in methodList) 
{ 
    try 
    { 
     info.action(); 
    } 
    catch(InvalidOperationException) 
    { 
     problem = string.Format("{0} failed", info.identifier); 
     break; 
    } 
} 
if(problem != null) 
{ 
    //notify 
} 
+0

Einige Methoden sind 'Func <>', brauchen Parameter, etc. Die Idee, aufgerufene Methode mit Nachricht zuzuweisen, ist gut, aber noch nicht soweit gekocht, dass es brauchbar ist. – Sinatr