C# Programm Fehlermeldung elegant umgehen

Griffindor01

Cadet 3rd Year
Registriert
Feb. 2021
Beiträge
33
Moin Gemeinde!

Sitze gerade für die Schule an einem Programmier-Projekt. Nun habe ich das Problem, dass ich einer Variable die Eingabe des Benutzers zuweise. Wenn dieser jedoch nichts eingibt, stützt das Programm logischerweise ab und es kommt in Visial Studio die Fehlermeldung, dass nichts übergeben werden konnte.

Habe schon überlegt, wie ich das lösen kann, aber bisher haben alle meine Bemühungen nicht geklappt.

Würde gerne entweder falls der Benutzer nichts eingeben sollte der Variable automatisch den Wert 0 zuweisen oder wenn das einfacher ist eine Fehlermeldung ausgeben lassen wie "Keine Eingabe erfasst. Bitte überprüfen.", nach der erneut abgefragt wird.

Wie setze ich das am einfachsten um? Sollte nicht zu komplex sein, da Schülerniveau
 
  • Gefällt mir
Reaktionen: Galaxius01
Initialisier sie vorher mit null. Nicht unassigned lassen.

dann so:
C#:
String ob = null;
if (ob is null) {
    Console.WriteLine("Keine Eingabe erfasst. Bitte überprüfen");
}
else {
    Console.WriteLine("Es wurde was eingegeben);
}
 
  • Gefällt mir
Reaktionen: Langsuan
Nachdem du schreibst, es soll danach erneut gefragt werden, ist mir eingefallen, neulich etwas ähnliches umgesetzt zu haben. Ist halt nun die Frage, ob das für dich nicht noch zu komplex ist:

C#:
Console.WriteLine("Ihre Eingabe bitte:"); //Aufforderung für den Benutzer zur Eingabe
bool retry = false; //Default value ist "false"
string value = null;

//Wird ausgefuehrt, wenn 'value = Console.ReadLine()' keine Eingabe enthaelt
while (string.IsNullOrWhiteSpace(value))
{
    if (retry) //prueft "retry" - wird beim 1. Mal uebersprungen, da ja oben auf "false" gesetzt
    {
        Console.WriteLine("Keine Eingabe erfasst. Bitte überprüfen.");
    }

    value = Console.ReadLine(); //Nimmt Benutzereingabe entgegen    
    retry = true; //setzt "retry" auf "true"
}

Wie aus den Code Kommentaren zu entnehmen, setzte ich meine beiden Variablen "retry" und "value" initial auf deren Default-Wert, um gezielt in die while-Schliefe zu laufen.
Eine while-Schleife wird so lange ausgeführt, wie eine definierte Annahme zutreffen ist. In diesem Fall also die Annahme die Variable 'value' enthält keinen Wert, ist also NULL, oder der Wert ist leer, also "".

Meine If-Condition wird beim ersten Durchlaufen der while-Schleife den Wert der Variable "retry" mit 'false' vorfinden, also ihren Inhalt nicht ausführen, macht also schlicht mit der Codeausführung darunter weiter.

Hier nehme ich die Benutzereingabe entgegen - diese kann jetzt einen Wert enthalten, oder eben leer sein.
Direkt darunter setzte ich "retry" nun auf 'true', um beim evtl. zweiten Durchlauf nun folglich den gewünschten Text ausgeben zu lassen.
Ist die Eingabe bereits beim ersten Mal valide, wird die Schleife kein zweites Mal ausgeführt, weil die Annahme "string.IsNullOrWhiteSpace(value)" nichtzutreffend ist.

Kann natürlich noch erweitert werden, wenn die Anforderung dahingehend ist, der Benutzer soll nicht nur keine leeren Werte eingeben, sondern auch keine "falschen" Werte, das überlass ich aber wieder dir. :-)
 
  • Gefällt mir
Reaktionen: madmax2010, rambodieschen, leander19961 und eine weitere Person
Dazu noch ein allgemeiner Hinweis:
  • Die Eingabe (User) / Übergabe (Methoden) nach besten Wissen prüfen - und sei es, dass überhaupt was eingegeben wurde
  • Funktionale Blöcke mit einem try-catch absichern

Befolgt man diese zwei einzelnen Schritte, ist der Code relativ stabil. Befolgt man es nicht, stürzt er vermutlich permanent ab.
 
  • Gefällt mir
Reaktionen: Big R
Keine Eingabe hat aber nur ganz selten "null" zur Folge. Wenn es ein Eingabefeld in einer UI ist, ist ein Leer-String viel üblicher, deshalb ist der Weg von evilbaschdi deutlich sinnvoller. Auch über ein ReadLine wird man kaum einen null-String erhalten.

Unabhängig davon kann es auch sinnvoll sein, auf gewisse Validierungsmechanismen zu setzen, je nach verwendeter UI-Technologie - vorausgesetzt eben, es ist eine UI-Anwendung.
 
Also a) Variablen immer initialisieren
b) sofern ihr schon soweit seid mit dem Stoff, benutze ein einfaches try-catch-Konstrukt
 
Warum a)? Bitte erklären. Ich persönlich sehe den Sinn in einer Sprache wie C# nicht.
Zu b): Klingt für mich so, als würde man dann Exceptions zur Programmflusssteuerung nutzen. Eine falsche Eingabe des Benutzers würde ich nicht als "Ausnahme" sehen, dass etwas unerwartetes passiert, sondern eher als etwas "normales". Zumal die Frage ist, wie die Exception überhaupt geworfen wird? Wer ist dafür verantwortlich? Und auf welche Exception-Klasse sollte hier konkret reagiert werden?
 
  • Gefällt mir
Reaktionen: Backfisch
zu a) Garbage in - Garbage out

Explizite Initialisierung ist manchmal notwendig aber immer besser, zb kannst du dann auch auf implizit typisierte Variablen zurückgreifen (erleichtert späteres Refactoring vom Code). Explizite Initialisierung zeigt einfach viel besser die Gedanken der Entwickler·innen.
 
Ich finde explizite Typisierung zeigt auch viel besser die Gedanken der Entwickler, ich verstehe ehrlich gesagt den Sinn der impliziten Typisierung nicht so. Die Lesbarkeit wird durch implizite null-Zuweisungen auch nur in den seltensten Fällen verbessert. Es gibt natürlich immer Ausnahmen, ein "bool retry = false," finde ich schon okay, um es ausdrucksstark zu machen. Den string mit null zu initialisieren halte ich wiederum nicht wirklich vorteilhaft für die Lesbarkeit. Da würde es deutlich mehr bringen, Wert auf kleine Funktionen zu legen.

Und welchen Vorteil hat das nun mit der null-Initialisierung in Bezug auf implizite Typen? Sehe ich irgendwie nicht so richtig.

Meiner Meinung nach sollte man eh versuchen, Variablen so weit es geht zu vermeiden. Also ich meine damit aber wirklich nur Variablen, die auch variable Werte haben. Also möglichst häufig readonly in C# bzw final in Java zu verwenden. Warum? Weil es die Fehlersuche durchaus erleichtert, wenn sich die Werte der Variablen nicht ständig ändern, weil dann klar ist, dass an dieser Stelle der Wert der Variable gesetzt (und ggf. dabei ermittelt wird) und danach nur noch dieser Wert verwendet wird. Der Nebeneffekt ist, dass man dann eben auch direkt sinnvolle Werte für die Initialisierung verwendet.
 
Zuletzt bearbeitet:
Danke für eure zahlreichen Antworten! In meinem Fall hat aber leider noch nichts wirklich geholfen ...
Anbei mein Code, zu Übungszwecken sollte ein Währungsrechner programmiert werden, der reversibel Euro in USD umwandelt. Der Programmcode an sich funktioniert super, nur dieses Extra-Feature mit der Meldung, wenn die Eingabe leer ist, hätte ich gerne noch mit enthalten als kleiner Perfektionist.
Das übergeordnete Thema ist im Unterricht nun die GUI-Programmierung. Die entsprechenden Methoden unten werden also nach entsprechendem Klick auf im GUI platzierte Buttons (Steuerelement) ausgeführt.


Sehe 2 Probleme:

Zum einen definiere ich die Variablen für die Euro und Dollar Werte direkt als double, wodurch sie nicht den Wert "null" haben können oder die Abfrage string.IsNullOrWhiteSpace funktioniert (habe nichts vergleichbares für einen leeren double gefunden).

Habe daher schon probiert gehabt, die beiden Variablen erst im weiteren Verlauf nach der Abfrage des Strings schlussendlich in einen double umzuwandeln und das Problem mithilfe der Schleifen, wie von @evilbaschdi beschrieben.
Das Programm ließ sich ausführen, aber reagierte nicht mehr, sobald die Eingabe leer war (musste über den Taskmanager beendet werden).
Meine Vermutung: Ich ermögliche dem Nutzer ja gar nicht, eine neue Eingabe zu tätigen (konnte noch nicht herausfinden, wie ich einem Nutzer es im GUI ermögliche, eine neue Eingabe während der Laufzeit des Programmes zu machen. Bisher wird ja nur die Eingabe im Textfeld zugewiesen, die vor dem Klick auf den Button getätigt wurde) und daher loopt sich die Schleife ins unendliche.

Würde mich über eure Hilfe freuen, wie ich das ganze möglichst einfach umsetzen kann.
Ansonsten lasse ich das wohl erstmal, da dies nicht in der Aufgabenstellung gefordert war und ein Zusatz von mir wäre, der vielleicht einfach mit meinen Kenntnissen sehr schwer umsetzbar wäre.

Nachfolgend der Code!

Grüße



C#:
 private void buttonEuroNachUSD_Click(object sender, EventArgs e)
        {
            
            // Euro-Wert wird gelesen und in der Variable euro gespeichert, dazu findet eine Konvertierung vom              Datentyp String zu double statt.
           
            double euro = Math.Round(Convert.ToDouble(textBoxEuro.Text), 2);
           
            // Umrechnung von Euro nach US-Dollar (Kurs: Stand 13.02.2022, 22:15 Uhr).
            double usdollar = Math.Round(euro * 1.14, 2);

            // Gegenwert des Euro-Wertes wird in US-Dollar ausgegeben, Datentyp wird nun reversibel in einen              String umgewandelt.
            textBoxUSDollar.Text = usdollar.ToString();
            




        }

        private void buttonUSDnachEuro_Click(object sender, EventArgs e)
        {
            // US Dollar Wert wird gelesen und in der Variable usdollar gespeichert, dazu findet eine                     
            Konvertierung vom Datentyp String zu double statt.
            
            double usdollar = Math.Round(Convert.ToDouble(textBoxUSDollar.Text), 2);

            // Umrechnung von US-Dollar nach Euro (Kurs: 13.02.2022, 22:15 Uhr).
            double euro = Math.Round(usdollar * 0.88, 2);

            // Gegenwert des US Dollar Wertes wird in Euro ausgegeben, Datentyp wird nun reversibel in einen                String umgewandelt.
            textBoxEuro.Text = euro.ToString();
        }
 
Prinzipiell ist das immer dasselbe: Eingabe holen, Eingabe prüfen, fertig.
Was sich unterscheidet ist die Art der Prüfung, je nachdem, was gebraucht wird.

Je nachdem wie aktuell euer C# ist, ist "der beste Weg" ein passendes Design Pattern:

C#:
if(var input is int inputValue)
{
// okay
// Eingabe steckt jetzt in inputValue, ABER der Scope ist dieser Block hier => muß ggfs. übergeben werden
}
else
{
// not okay
// Je nach Anforderung kann man den Benutzer neu fragen, oder man wirft eine Ausnahme. Oder sogar beides, wenn es eine "Parent" Methode gibt, die "unsere" Ausnahme abfängt und behandelt.
}

Sicherheitshalber, "Input" muß natürlich nicht deklariert werden, den gibts schon aus der Abfrage an den Benutzer. Das "var" nur für allgemeinere Gültigkeit. Read() Methoden aus System.Console geben normalerweise Strings.
 
Griffindor01 schrieb:
Moin Gemeinde!

Sitze gerade für die Schule an einem Programmier-Projekt.
Werden jetzt hier Schulaufgaben gelöst? So weit ich das kenne, gibt man dem Fragesteller in der Hinsicht mal Hinweise, aber man löst nicht seine Schulaufgaben, davon lernt er nämlich nichts. - Außerdem ist es gegenüber anderen Schülern unfair, welche die Aufgabe selbstständig lösen.
 
  • Gefällt mir
Reaktionen: Backfisch
Anhaltspunkte find ich okay und Selbstinitiative erst recht, alles andere bleibt in dubio pro reo oder so.

Das, plus Hausaufgaben scheinen in letzter Zeit hier niemanden mehr zu interessieren. 🤷‍♀️
 
RalphS schrieb:
Das, plus Hausaufgaben scheinen in letzter Zeit hier niemanden mehr zu interessieren.
Wenn sich Fragen beim lösen von Hausaufgaben auftreten hier nachzufragen ist grundsätzlich nicht verwerflich. Problematisch wirds erst, wenn man sich die Aufgabe abnehmen lassen will.
Interessant fand ich diesbezüglich den Satz:
Griffindor01 schrieb:
Sollte nicht zu komplex sein, da Schülerniveau
Klingt so ein bisschen nach: "Brauch ne Lösung aber die sollte so primitiv sein das niemand merkt, das ich in nem Forum gefragt hab, sondern es so aussieht als wäre ich selbst drauf gekommen." :-)
 
  • Gefällt mir
Reaktionen: Backfisch und madmax2010
Jede User Eingabe kommt erstmal als String an, auch in Deinem Code. Das wird dann früher oder später in andere Datentypen konvertiert.

Vor der Konvertierung könntest Du auf NulllOrWhiteSpace prüfen oder noch optimalerweise per Regex auf nur Zahlen, aber das geht wahrscheinlich schon zu weit.

Ansonsten könntest Du auch Double Werte mit negativen Werten vorbelegen oder als nullable definieren um eine Zuweisung zu überprüfen...

Generell muss die Fehlerfälle ausschließen mit if Abfragen, um nicht zu einem Absturz zu führen, die grobe Struktur dafür ist:
C#:
private void buttonEuroNachUSD_Click(object sender, EventArgs e)
{    
  if(!string.IsNullOrWhiteSpace(textBoxEuro.Text))
  {
    if(checkIfCastableToInt(textBoxEuro.Text))
    {
       //Dein Code
    }
  }
}

private bool checkIfCastableToInt(string input)
{
  //Dein Code
}

checkIfCastableToInt musst Du auch implementieren, entweder per regex, oder hart casten und mit try...catch abfangen z.B.


andy_m4 schrieb:
Wenn sich Fragen beim lösen von Hausaufgaben auftreten hier nachzufragen ist grundsätzlich nicht verwerflich. Problematisch wirds erst, wenn man sich die Aufgabe abnehmen lassen will.
Interessant fand ich diesbezüglich den Satz:

Klingt so ein bisschen nach: "Brauch ne Lösung aber die sollte so primitiv sein das niemand merkt, das ich in nem Forum gefragt hab, sondern es so aussieht als wäre ich selbst drauf gekommen." :-)
Könnte auch heißen, bitte nicht zu schwierig erklären oder zu schwierige, da ich noch nicht so weit bin und es mit einfachen Mitteln lösen möchte...
 
Zuletzt bearbeitet:
Einige haben meine Aussage heute früh etwas missverstanden. Wichtig sind sowohl Validierung als auch Exception Handling. Und zwar immer und an allen Stellen. Nur so erzeugt man guten Prozessfluss.

Einige haben ihn ja schon darauf hingewiesen. Andere geben leider fatale Ratschläge zu "einfach die Exception abfangen". Da muss man vorsichtig sein und nicht seiner Faulheit nachgeben.
 
  • Gefällt mir
Reaktionen: skiefis, Big R und madmax2010
Drexel schrieb:
checkIfCastableToInt musst Du auch implementieren, entweder per regex, oder hart casten und mit try...catch abfangen z.B.
Nein, das macht man mit int.TryParse
 
  • Gefällt mir
Reaktionen: Ephesus, madmax2010, andy_0 und eine weitere Person
IMHO sollte man vorhandene Funktionen nutzen, wenn sie das Framework anbietet. Das ist nicht nur sicherer (die wissen was sie tun), sondern spart auch Zeit.
 
  • Gefällt mir
Reaktionen: skiefis und Backfisch

Ähnliche Themen

K
2
Antworten
31
Aufrufe
3.024
Zurück
Oben