none
Try und Catch und Behebung von Ausnahme RRS feed

  • Frage

  • Hallo

    ich habe eine kleine Frage. Ich muss eine Übung für ein Fach an der Uni lösen. Es geht darum einen kleine Taschenrechner (mittels Konsole) zu programmieren. Es ist wirklich etwas was sehr simples. Es werden zwei Zahlen und ein Operator eingegeben, aus welchen man nun das Ergebnis berechnen soll. Es sollen bei den Programm auch Fehleingaben abgefangen werden. Dies soll mittels Catch geschehen. Habe alles bisher ordentlich umgesetzt. Was mich aber stört ist das nur der Fehler angegeben wird aber keine Lösung direkt eingeben werden kann. Nun hatte ich mir gedacht, um das Problem erst einmal zu beheben einfach die Eingabe solange wiederholen lasse bis eine "ordentliche Zahl" eingegeben wurde. Meine Frage ist nun ob es "erlaubt" ist bzw. ob der Catch Block dafür da ist um Probleme zu beheben oder nur dafür da ist um den Fehler Auszugeben ?

    MfG Marvin 


    • Bearbeitet Marvin.R Donnerstag, 14. April 2016 13:16
    Donnerstag, 14. April 2016 13:13

Antworten

  • Hallo Marvin,

    das try-catch-finally Konzept dient erstmal dem Abfangen und Verarbeiten von Fehlern.

    Das heißt dass du Exceptions abfangen kannst um sie zu loggen und dann doch wieder neu zu werfen (throw), du aber auch nur Ressourcen freigeben kannst (in finally) um danach die Anwendung abstürzen zu lassen. Genauso kannst du aber auch diverse Exceptions abfangen die du von Anfang an näher auswerten kannst. Beispielsweise kann man eine DivideByZeroException recht eindeutig zuordnen und den Fehler oftmals auch beheben.

    Du wirst momentan vermutlich versuchen einen eingelesenen String in eine Zahl umzuwandeln und das so lange zu probieren bis der Benutzer eine funktionierende Zahl eingegeben hat:

    int result;
    bool flag=true;
    do{
      try{
        result = int.Parse(Console.ReadLine());
        flag=false;
      }
      catch(FormatException){
        Console.WriteLine("Ungültige Zahl.");
      }
      catch(OverflowException){
        Console.WriteLine("Die Zahl ist zu groß oder zu klein.");
      }
    }while(flag);

    Das kann man durchaus so machen und bietet dir hier beispielsweise die Möglichkeit zu erkennen woran das Parsen gescheitert ist. (Vergleiche MSDN Doku)

    Zu gleich würde ich in den meisten Fällen jedoch die TryParse-Methode für so etwas nutzen:

    int result;
    while(!int.TryParse(Console.ReadLine(), out result)){
      Console.WriteLine("Fehlerhafte Eingabe.");
    }

    Es gibt auch Stellen bei denen man beides kombinieren sollte. Beispielsweise kann man bei Dateioperationen mittels File.Exists prüfen ob eine Datei existiert. Trotzdem kann es passieren das direkt nach dieser Prüfung die Datei gelöscht bzw. erstellt wird. Entsprechend sollte man hier trotzdem noch Exceptions abfangen und diese passend auswerten.

    Ergänzung zu deiner Antwort: Vermeide es die Basisklasse System.Exception abzufangen. Das sagt dir wirklich nichts. Es muss nicht mal zwingend mit der Eingabe zu tun haben, da auch irgendwo anders im .NET Framework ein Fehler aufgetreten sein könnte.

    Deine Idee mit der bool-Variable ist nicht schlecht und habe ich in meinem ersten Beispiel auch umgesetzt (dort heißt die Variable flag). Du musst sie nur am Ende des try-Blocks auf true setzen um die Schleife damit beim nächsten Durchlaufversuch zu beenden. Das Ende des try-Blocks wird schließlich nur dann erreicht, wenn alles andere Fehlerfrei durchlief.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets


    Donnerstag, 14. April 2016 13:28
    Moderator
  • Hallo Marvin,

    die Hinweismeldung, dass die Methode nichts zurückgibt, kommt, da es eben auch passieren kann, dass die Schleife gar nicht erst durchlaufen wird. Daher solltest Du, wie VS es wünscht, einen Standardwert für den Fall, dass keine andere return Zeile ausgeführt wird, am Ende der Methode zurückgeben.

    Ansonsten kann es passieren, dass der Aufrufer eben "nichts" zurückerhält aber einen Wert (in welcher Form auch immer erwartet). Da die Variable, die die Rückgabe speichert, dann unter Umständen null enthält, kommt es bei der weiteren Verarbeitung zu Fehlern, wenn der Entwickler nicht explizit darauf prüft.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Donnerstag, 14. April 2016 14:04
    Moderator

Alle Antworten

  • Hallo Marvin,

    zeig doch erstmal den Code, den Du bisher hast und beschreib anhand dieses Codes, was Du wo erreichen möchtest.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Donnerstag, 14. April 2016 13:14
    Moderator
  • public static int einlesen() { bool richtige_eingabe = false; int zahl = 0; while (richtige_eingabe == false) { try { zahl = Convert.ToInt32(Console.ReadLine()); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } }


    Sprich ich lese im While-block eine Zahl ein und Teste diese. Sollte nun der Benutzer statt einer Zahl ein Buchstaben eingeben bekommt der Benutzer ja die Fehlermeldung. Ich hatte nun die Idee, das wenn eine Ausnahme festgestellt wird das im Catch-Block eine weiter Variable nennen wir sie mal  test z.B. auf true gesetzt wird. Danach wollte ich in mit einer if-Anweisung (nach dem Catch-Block) abfragen ob test true oder false ist und damit zu entscheiden ob die Zahl erneut eingeben werden muss (und somit die While-Schleife erneut durchlaufen werden muss) oder ob die Zahl bereits richtig eingegeben ist

    MfG

    Donnerstag, 14. April 2016 13:27
  • Hallo Marvin,

    das try-catch-finally Konzept dient erstmal dem Abfangen und Verarbeiten von Fehlern.

    Das heißt dass du Exceptions abfangen kannst um sie zu loggen und dann doch wieder neu zu werfen (throw), du aber auch nur Ressourcen freigeben kannst (in finally) um danach die Anwendung abstürzen zu lassen. Genauso kannst du aber auch diverse Exceptions abfangen die du von Anfang an näher auswerten kannst. Beispielsweise kann man eine DivideByZeroException recht eindeutig zuordnen und den Fehler oftmals auch beheben.

    Du wirst momentan vermutlich versuchen einen eingelesenen String in eine Zahl umzuwandeln und das so lange zu probieren bis der Benutzer eine funktionierende Zahl eingegeben hat:

    int result;
    bool flag=true;
    do{
      try{
        result = int.Parse(Console.ReadLine());
        flag=false;
      }
      catch(FormatException){
        Console.WriteLine("Ungültige Zahl.");
      }
      catch(OverflowException){
        Console.WriteLine("Die Zahl ist zu groß oder zu klein.");
      }
    }while(flag);

    Das kann man durchaus so machen und bietet dir hier beispielsweise die Möglichkeit zu erkennen woran das Parsen gescheitert ist. (Vergleiche MSDN Doku)

    Zu gleich würde ich in den meisten Fällen jedoch die TryParse-Methode für so etwas nutzen:

    int result;
    while(!int.TryParse(Console.ReadLine(), out result)){
      Console.WriteLine("Fehlerhafte Eingabe.");
    }

    Es gibt auch Stellen bei denen man beides kombinieren sollte. Beispielsweise kann man bei Dateioperationen mittels File.Exists prüfen ob eine Datei existiert. Trotzdem kann es passieren das direkt nach dieser Prüfung die Datei gelöscht bzw. erstellt wird. Entsprechend sollte man hier trotzdem noch Exceptions abfangen und diese passend auswerten.

    Ergänzung zu deiner Antwort: Vermeide es die Basisklasse System.Exception abzufangen. Das sagt dir wirklich nichts. Es muss nicht mal zwingend mit der Eingabe zu tun haben, da auch irgendwo anders im .NET Framework ein Fehler aufgetreten sein könnte.

    Deine Idee mit der bool-Variable ist nicht schlecht und habe ich in meinem ersten Beispiel auch umgesetzt (dort heißt die Variable flag). Du musst sie nur am Ende des try-Blocks auf true setzen um die Schleife damit beim nächsten Durchlaufversuch zu beenden. Das Ende des try-Blocks wird schließlich nur dann erreicht, wenn alles andere Fehlerfrei durchlief.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets


    Donnerstag, 14. April 2016 13:28
    Moderator
  • public static int einlesen()
            {
                bool richtige_eingabe = false;
                bool test = false;
                int zahl = 0;
               
                while (richtige_eingabe == false)
                {
                    try
                    {
                        zahl = Convert.ToInt32(Console.ReadLine());
                    }
                    catch (FormatException ex)
                    {
                        Console.WriteLine(ex.ToString());
                        test = true;
                    }
                    catch (OverflowException ex)
                    {
                        Console.WriteLine(ex.ToString());
                        test = true;
                    }
    
                    if(test == false)
                    {
                        richtige_eingabe = true;
                    }
                    else
                    {
                        Console.Write("Geben Sie die erste Zahl ein: ");
                        richtige_eingabe = false;
                        test = false;
                    }
    
                }
    
                return zahl;
            }

    Habe es jetzt so Umgesetzt und es funktioniert. Eine Frage hätte ich aber noch. Wenn ich im ersten Block der If-Anweisung sprich dort wenn keine Exception vorliegt und die Schleife verlassen wird (richtige_eingabe = true), den Return-Befehl setzte wird mir angezeigt das kein Return-Befehl vorhanden sein oder anders gesagt das nichts an die Funktion zurückgegeben wird. Erst wenn ich das Return nach der Schleife schreibe ist alles ok. Warum ist das so? 

    MfG


    • Bearbeitet Marvin.R Donnerstag, 14. April 2016 13:51
    Donnerstag, 14. April 2016 13:50
  • Hallo Marvin,

    die Hinweismeldung, dass die Methode nichts zurückgibt, kommt, da es eben auch passieren kann, dass die Schleife gar nicht erst durchlaufen wird. Daher solltest Du, wie VS es wünscht, einen Standardwert für den Fall, dass keine andere return Zeile ausgeführt wird, am Ende der Methode zurückgeben.

    Ansonsten kann es passieren, dass der Aufrufer eben "nichts" zurückerhält aber einen Wert (in welcher Form auch immer erwartet). Da die Variable, die die Rückgabe speichert, dann unter Umständen null enthält, kommt es bei der weiteren Verarbeitung zu Fehlern, wenn der Entwickler nicht explizit darauf prüft.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Donnerstag, 14. April 2016 14:04
    Moderator
  • Die zusätzliche Variable test ist eigentlich nutzlos. richtige_eingabe erfüllt den selben Zweck. Wenn du mal in meinen Code guckst, dann siehst du das ich auch nur eine bool'sche Variable flag habe.

    Das return zahl; kannst du überall in deiner Methode aufrufen, sofern zahl schon deklariert und initialisiert wurde. Beachte dass return in C# klein geschrieben wird.
    Zitiere Fehlermeldungen bitte immer. Eine Interpretation lässt i.d.R. die hälfte weg und wir können dir nicht so gut helfen.

    Sofern du C# 6 verwendest kannst du die beiden catch-Blöcke übrigens auch verbinden:

    try
    {
        zahl = Convert.ToInt32(Console.ReadLine());
    }
    catch (Exception ex) when (ex is FormatException || ex is OverflowException)
    {
        Console.WriteLine(ex.ToString());
        test = true;
    }
    Dein Code hat übrigens keinen Vorteil gegenüber meinem Dreizeiler mit TryParse...


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Donnerstag, 14. April 2016 14:05
    Moderator
  • Leider kenne ich mich mit den TryParse nicht aus bzw. habe mich damit noch nicht beschäftigt. Was die Kombination der Blöcke angeht. Was ist (ich bezweifle das dieser Fall bei einen solch simplen Programm auftreten wird) wenn es aber dazu kommen soll das beide Ausnahmen auftreten? Werden dann beide angezeigt oder nur eine Ausnahme?
    • Bearbeitet Marvin.R Donnerstag, 14. April 2016 14:47
    Donnerstag, 14. April 2016 14:46
  • In der MSDN Dokumentation zu TryParse findest du weitere Informationen, auch nochmal ein anderes Beispiel. Es macht praktisch nichts anderes als die try-catch-Konstruktion, aber eben in eine eigene Funktion weg gekapselt. Meiner Meinung nach solltet du dir das zumindest mal anschauen.

    Von einem Code wirst du immer nur eine Exception im selben Thread zur selben Zeit bekommen. Das heißt, dass so oder so nur eine behandelt werden muss, man weiß eben nur nicht welche.
    Wenn du mit mehreren Threads arbeitest kommt es aber auch zu keinem Problem, da sich Exceptions nicht Threadübergreifend abfangen lassen.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Donnerstag, 14. April 2016 15:34
    Moderator