wake-up-neo.com

C # -verschachtelte Try-Catch-Anweisungen oder -Methoden?

Einfache Best-Practice-Frage.

Sollten Sie sich verschachteln, versuchen Sie es mit catch-Anweisungen oder verwenden Sie einfach Methoden.

Wenn Sie beispielsweise eine Methode haben, mit der eine Datei geöffnet und geschlossen wird, haben Sie das Öffnen und Schließen außerhalb des try-Catch bzw. das Schließen im finally-Block.

Wenn nun Ihre offene Methode fehlschlägt, würde die Methode richtig behaupten? Sollte man das also in einen try catch-Block einschließen oder sollte das von einer anderen Methode aufgerufen werden, die wiederum einen try catch-Block darstellt?

17
ghost

Im Kontext einer Methode, die eine Datei öffnet, würde ich eine using-Anweisung gegen einen try-catch verwenden. Die using-Anweisung stellt sicher, dass Dispose aufgerufen wird, wenn eine Ausnahme auftritt.

using (FileStream fs = new FileStream(file, FileMode.Open))
{
    //do stuff
}

macht dasselbe wie:

FileStream fs;
try
{
     fs = new FileStream(file, FileMode.Open);
     //do Stuff
 }
 finally
 {
        if(fs!=null)
           fs.Dispose();
 }
15
cgreeno

Jetzt, da wir Lambdas und Typinferenz und einige andere Dinge haben, gibt es eine in anderen Sprachen übliche Redewendung, die jetzt in C # sehr viel Sinn ergibt. In Ihrem Beispiel ging es darum, eine Datei zu öffnen, etwas zu tun und sie dann zu schließen. Nun, jetzt können Sie eine Hilfsmethode erstellen, die eine Datei öffnet und sich auch darum kümmert, dass sie geschlossen, entsorgt und bereinigt wird. Sie rufen jedoch ein Lambda auf, das Sie für den Teil "do stuff" bereitstellen. Auf diese Weise können Sie die komplizierten Dinge zum Ausprobieren/Auffangen/Entsorgen/Aufräumen an einem Ort aufbewahren und dann immer wieder verwenden.

Hier ist ein Beispiel:

public static void ProcessFile(string filePath, Action<File> fileProcessor)
{
  File openFile = null;

  try
  {
    openFile = File.Open(filePath); // I'm making this up ... point is you are acquiring a resource that needs to be cleaned up after.

    fileProcessor(openFile); 
  }
  finally
  {
    openFile.Close(); // Or dispose, or whatever.
  }
}

Jetzt müssen sich Aufrufer dieser Methode nicht mehr darum kümmern, wie sie die Datei öffnen oder schließen/entsorgen sollen. Sie können so etwas tun:

Helpers.ProcessFile("C://somefile.txt", f => 
 {
   while(var text = f.ReadLine())
   {
     Console.WriteLine(text);
   }
 });
11
Charlie Flowers

Dies ist eine Stilfrage, aber ich versuche nie mehr als eine Ebene von try/catch/finally in einer einzigen Methode zu haben. An dem Punkt, an dem Sie einen verschachtelten Versuch unternommen haben, haben Sie mit ziemlicher Sicherheit gegen die 1-Funktion = 1-Operation verstoßen und sollten eine zweite Methode anwenden.

7
JaredPar

Kommt darauf an, was Sie versuchen, aber in den meisten Fällen sind geschachtelte Versuche/Fänge ein Zeichen für eine überkomplexe Funktion (oder für einen Programmierer, der nicht genau weiß, wie Ausnahmen funktionieren!).

Im Fall der geöffneten Datei würde ich einen IDisposable-Inhaber und eine using-Klausel verwenden und so auf die Notwendigkeit eines expliziten Versuchs/Fangs verzichten.

4
Pontus Gagge

Wie wäre es, wenn Sie verwandten Code haben, der nicht unbedingt zu einer eigenen Funktion gehört? Wäre das dann richtig?

try
{
  // Part 1 Code Here

  try
  {
    // Part 2 Code Here
  }
  catch (Exception ex)
  {
    // Error from Part 2
  }
}
catch (Exception ex) 
{
  // Error from Part 1
} 
3
Sean

Die meiste Zeit habe ich die verschachtelten try/catch-Blöcke in Funktionen aufgeteilt. Aber ich habe manchmal Code geschrieben, um alle von meiner Anwendung ausgelösten, nicht erfassten Ausnahmen zu erfassen und zu protokollieren. Aber was ist, wenn der Protokollierungscode fehlschlägt? Ich habe also noch einen Versuch unternommen, um zu verhindern, dass der Benutzer das standardmäßige Dialogfeld für nicht behandelte .NET-Ausnahmen sieht. Aber auch dieser Code könnte sehr einfach in Funktionen umgestaltet werden, anstatt in verschachtelte Try/Catch-Blöcke.

try
{
    try
    {
        DoEverything(); 
    }
    catch (Exception ex)
    {
        // Log the exception here
    }
}
catch (Exception ex)
{
    // Wow, even the log is broken ...
}
1
Brian Ensink
//create a switch here and set it to 0 
try
{
    DoChunk1(); 
    //looks good. set the switch to 1
}
catch (Exception ex)
{
    // Log the exception here
}

// überprüfe den Schalter, wenn er zu diesem Zeitpunkt noch Null ist, dann kannst du dein Programm hier anhalten; Andernfalls setzen Sie den Schalter auf Null und führen Sie die nächste try catch-Anweisung aus. Stimmen Sie voll und ganz der Zerlegung zu, wie oben erwähnt

try {DoChunk2 (); //sieht gut aus. setze den Schalter auf 1} catch (Exception ex) {// Logge die Exception hier}

0
Ronan Masangcay