Kapitel: Mein erstes Programm

Ein visuellerer Taschenrechner

Befehl: Console.Clear, Console.ReadKey

Erinnerst du dich an Was können wir schon? Ein Taschenrechner? Der hat nach Zahl a gefragt, dann Enter, dann nach dem Rechenzeichen, wieder Enter, dann Zahl b, wieder Enter. Mit Console.Clear() und Console.ReadKey() bauen wir jetzt eine Version, die sich mehr wie ein echter Taschenrechner anfühlt: Sie reagiert sofort auf jeden Tastendruck und zeigt die Eingabe live in einer Zeile an.

Der Plan

  • Jede Ziffer, die du tippst, hängt sich direkt an die Anzeige an.
  • Eines von + - * / markiert den Wechsel von Zahl a zu Zahl b.
  • Enter rechnet die Eingabe aus (das ist unser =).
  • ESC beendet das Programm.
Wie schon beim ersten Taschenrechner gehen wir auch hier davon aus, dass halbwegs sinnvoll getippt wird - z.B. erst Ziffern, dann ein Rechenzeichen, dann wieder Ziffern. Eine echte Absicherung gegen jede denkbare Tastenfolge würde den Rahmen hier sprengen.

Schritt 1: Was wir uns merken müssen

Anders als beim ersten Taschenrechner lesen wir diesmal nicht mit ReadLine ganze Zeilen ein, sondern bauen die Zahlen Zeichen für Zeichen selbst zusammen. Dafür brauchen wir etwas mehr Zustand:

string zahlA = "";
char operatorZeichen = ' ';
bool hatOperator = false;
string zahlB = "";
string ergebnisText = "";
bool beenden = false;
zahlA und zahlB sind hier bewusst string, nicht double - wir sammeln erstmal nur Ziffern-Zeichen ein. Erst wenn wir wirklich rechnen, wandeln wir sie mit double.Parse in Zahlen um, genau wie beim ersten Taschenrechner. hatOperator merkt sich, ob wir gerade zahlA oder zahlB füllen.

Schritt 2: Anzeige aufbauen und die Schleife starten

Bei jedem Schleifendurchlauf leeren wir die Konsole und bauen die Anzeige neu aus dem aktuellen Zustand zusammen:

while (beenden == false)
{
    Console.Clear();
    Console.WriteLine("Taschenrechner (ESC = Beenden, Enter = Ausrechnen)");

    string anzeige = zahlA;
    if (hatOperator)
    {
        anzeige = anzeige + operatorZeichen;
    }
    anzeige = anzeige + zahlB;
    if (ergebnisText != "")
    {
        anzeige = anzeige + " = " + ergebnisText;
    }

    Console.WriteLine(anzeige);

    // ... Taste einlesen kommt in Schritt 3 ...
}
anzeige wird stückweise zusammengebaut: erst zahlA, dann - falls schon vorhanden - das Rechenzeichen, dann zahlB, und ganz am Ende, falls schon ausgerechnet wurde, noch = und das Ergebnis. Am Anfang ist zahlA leer, hatOperator false und ergebnisText leer - die Anzeige zeigt also einfach nichts.

Schritt 3: Auf ESC und Enter reagieren

An die Stelle des Kommentars von eben kommt jetzt das Einlesen der Taste. Bisher hast du nur .KeyChar von Console.ReadKey() benutzt, um das eingetippte Zeichen zu bekommen. Für Sondertasten wie ESC oder Enter gibt es keinen sinnvollen KeyChar - stattdessen vergleichst du .Key mit einem Wert aus der Aufzählung ConsoleKey:

ConsoleKeyInfo taste = Console.ReadKey(true);

if (taste.Key == ConsoleKey.Escape)
{
    beenden = true;
}
else if (taste.Key == ConsoleKey.Enter)
{
    double a = double.Parse(zahlA);
    double b = double.Parse(zahlB);
    double ergebnis = 0;

    switch (operatorZeichen)
    {
        case '+':
            ergebnis = a + b;
            break;
        case '-':
            ergebnis = a - b;
            break;
        case '*':
            ergebnis = a * b;
            break;
        case '/':
            ergebnis = a / b;
            break;
    }

    ergebnisText = "" + ergebnis;
}
taste.Key == ConsoleKey.Escape ist im Grunde ein ganz normaler Vergleich, wie du ihn schon von if und Vergleichen kennst - nur dass hier eben Tasten statt Zahlen verglichen werden. Die Berechnung selbst ist exakt die gleiche switch-Anweisung wie beim ersten Taschenrechner.

Schritt 4: Ziffern und Rechenzeichen einsammeln

Zum Schluss kommen noch drei weitere else if dazu, die sich um alle anderen Tasten kümmern:

else if (hatOperator == false && char.IsDigit(taste.KeyChar))
{
    if (ergebnisText != "")
    {
        zahlA = "";
        zahlB = "";
        ergebnisText = "";
    }
    zahlA = zahlA + taste.KeyChar;
}
else if (hatOperator == false && (taste.KeyChar == '+' || taste.KeyChar == '-' || taste.KeyChar == '*' || taste.KeyChar == '/'))
{
    operatorZeichen = taste.KeyChar;
    hatOperator = true;
}
else if (hatOperator && char.IsDigit(taste.KeyChar))
{
    zahlB = zahlB + taste.KeyChar;
}
Die erste Bedingung prüft mit || (das kennst du aus dem Kapitel Mehrere Vergleiche), ob taste.KeyChar eines der vier Rechenzeichen ist. Der kleine Trick am Anfang: Wenn schon ein ergebnisText angezeigt wird und jetzt eine neue Ziffer kommt, will man ja eine ganz neue Rechnung starten - also werden zahlA, zahlB und ergebnisText erst geleert, bevor die neue Ziffer eingesammelt wird.

Das komplette Programm

string zahlA = "";
char operatorZeichen = ' ';
bool hatOperator = false;
string zahlB = "";
string ergebnisText = "";
bool beenden = false;

while (beenden == false)
{
    Console.Clear();
    Console.WriteLine("Taschenrechner (ESC = Beenden, Enter = Ausrechnen)");

    string anzeige = zahlA;
    if (hatOperator)
    {
        anzeige = anzeige + operatorZeichen;
    }
    anzeige = anzeige + zahlB;
    if (ergebnisText != "")
    {
        anzeige = anzeige + " = " + ergebnisText;
    }

    Console.WriteLine(anzeige);

    ConsoleKeyInfo taste = Console.ReadKey(true);

    if (taste.Key == ConsoleKey.Escape)
    {
        beenden = true;
    }
    else if (taste.Key == ConsoleKey.Enter)
    {
        double a = double.Parse(zahlA);
        double b = double.Parse(zahlB);
        double ergebnis = 0;

        switch (operatorZeichen)
        {
            case '+':
                ergebnis = a + b;
                break;
            case '-':
                ergebnis = a - b;
                break;
            case '*':
                ergebnis = a * b;
                break;
            case '/':
                ergebnis = a / b;
                break;
        }

        ergebnisText = "" + ergebnis;
    }
    else if (hatOperator == false && char.IsDigit(taste.KeyChar))
    {
        if (ergebnisText != "")
        {
            zahlA = "";
            zahlB = "";
            ergebnisText = "";
        }
        zahlA = zahlA + taste.KeyChar;
    }
    else if (hatOperator == false && (taste.KeyChar == '+' || taste.KeyChar == '-' || taste.KeyChar == '*' || taste.KeyChar == '/'))
    {
        operatorZeichen = taste.KeyChar;
        hatOperator = true;
    }
    else if (hatOperator && char.IsDigit(taste.KeyChar))
    {
        zahlB = zahlB + taste.KeyChar;
    }
}

Kurz zusammengefasst: Mit Console.Clear() und Console.ReadKey() reagiert dein Programm sofort auf jeden einzelnen Tastendruck, statt in grossen Häppchen mit ReadLine zu arbeiten - und du bestimmst selbst, was davon auf dem Bildschirm landet. Genau damit lassen sich schon kleine, interaktive Anwendungen bauen, die sich runder anfühlen als reine Frage-Antwort-Programme.

Weiter geht's mit: Richtig prüfen mit TryParse