September discount week
Tento týden až 80% sleva na e-learning týkající se jazyka C
50 % bodů zdarma na online výuku díky naší Slevové akci!

Lekce 7 - Ošetření uživatelských vstupů v C# .NET

V předešlém cvičení, Řešené úlohy k 6. lekci C# .NET, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

Dnes to bude takové oddechové, dokončíme si totiž naši kalkulačku, dále už ji nebudeme potřebovat a bylo by hezké ji dotáhnout do konce. Asi tušíte, že u ni chybí zabezpečení vstupů od uživatele, tím se bude zabývat dnešní C# tutoriál.

Připomeňme si kód naší kalkulačky:

Console.WriteLine("Vítejte v kalkulačce");
string pokracovat = "ano";
while (pokracovat == "ano")
{
    Console.WriteLine("Zadejte první číslo:");
    float a = float.Parse(Console.ReadLine());
    Console.WriteLine("Zadejte druhé číslo:");
    float b = float.Parse(Console.ReadLine());
    Console.WriteLine("Zvolte si operaci:");
    Console.WriteLine("1 - sčítání");
    Console.WriteLine("2 - odčítání");
    Console.WriteLine("3 - násobení");
    Console.WriteLine("4 - dělení");
    int volba = int.Parse(Console.ReadLine());
    float vysledek = 0;
    switch (volba)
    {
        case 1:
            vysledek = a + b;
        break;
        case 2:
            vysledek = a - b;
        break;
        case 3:
            vysledek = a * b;
        break;
        case 4:
            vysledek = a / b;
        break;
    }
    if ((volba > 0) && (volba < 5))
        Console.WriteLine("Výsledek: {0}", vysledek);
    else
        Console.WriteLine("Neplatná volba");
    Console.WriteLine("Přejete si zadat další příklad? [ano/ne]");
    pokracovat = Console.ReadLine();
}
Console.WriteLine("Děkuji za použití kalkulačky, aplikaci ukončíte libovolnou klávesou.");
Console.ReadKey();

Už jsme si jednou říkali, že bychom měli vstupy od uživatele vždy ošetřovat. Řeknu vám tajemství úspěšných a oblíbených aplikací, je velmi jednoduché: Počítají s tím, že je uživatel naprostý hlupák :) Čím hloupějšího uživatele budete předpokládat, tím větší úspěch budou vaše aplikace mít. Pokud zde uživatel zadá místo "ano" např. "ano " (ano mezera) nebo "Ano" (s velkým písmenem), program stejně skončí. To ještě nemusí být kvůli hlouposti, ale proto, že se překlepl. Může nám však zadat i něco úplně nesmyslného, např. "možná".

To není však největší problém našeho programu, když uživatel nezadá číslo, ale nějaký nesmysl, celý program se zastaví a spadne s chybou. Pojďme nyní tyto dva problémy opravit.

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

K ověření správnosti vstupu při jeho parsování můžeme místo metody Parse() použít metodu TryParse(). Metoda vrací true/false podle toho, jestli se parsování podařilo či nikoli. Jestli se ptáte, jak z metody tedy dostaneme naparsovanou hodnotu, tak ta se nám uloží do proměnné předané druhým parametrem. U parametru musíme uvést modifikátor out, zatím se jím nebudeme zatěžovat, budeme brát jako fakt, že to metoda TryParse() takhle má. Hodnota proměnné, kterou jsme takto předali do druhého parametru, bude ovlivněna. Ukážeme si to u prvního čísla, u druhého to bude samozřejmě analogické a jen to opíšeme. Ideálně bychom si na to měli vytvořit metodu, abychom nepsali 2x ten samý kód, ale zatím není vhodná doba se tímto zabývat, metody se naučíme definovat až u objektově orientovaného programování.

Console.WriteLine("Zadejte první číslo:");
float a;
while (!float.TryParse(Console.ReadLine(), out a))
    Console.WriteLine("Neplatné číslo, zadejte prosím znovu:");

Na kódu není nic složitého. Nejprve vyzveme uživatele k zadání čísla a deklarujeme proměnnou a. Následně přímo do podmínky while cyklu vložíme TryParse(), podmínku znegujeme operátorem !. Dokud tedy vrací false, bude se cyklus stále opakovat a vyzývat k novému zadání. Zadaný text z konzole se naparsuje do proměnné a je navráceno true. Pokud se parsování nepovede, je vráceno false.

Nyní se ještě podíváme na výběr operace a pokračování. Obě volby načítáme jako string i když to není úplně vhodné. U čísel to má opodstatnění, protože mohou mít délku větší než jeden znak a musí být odenterovány. U volby operací 1-4 ale vůbec nepotřebujeme načítat text a potvrzovat ho enterem, stačí načíst jediný znak z klávesnice a ten nemusíme ničím potvrzovat. K načtení jediného znaku slouží nám již známá metoda Console.ReadKey(). Abychom výsledek dostali jako char (znak), musíme na této metodě použít vlastnost KeyChar. Ve switchi nezapomínejme, že char se zapisuje do apostrofů.

char volba = Console.ReadKey().KeyChar;
float vysledek = 0;
bool platnaVolba = true;
switch (volba)
{
    case '1':
        vysledek = a + b;
        break;
    case '2':
        vysledek = a - b;
        break;
    case '3':
        vysledek = a * b;
        break;
    case '4':
        vysledek = a / b;
        break;
    default:
        platnaVolba = false;
        break;
}
if (platnaVolba)
    Console.WriteLine("Výsledek: {0}", vysledek);
else
    Console.WriteLine("Neplatná volba");

Do proměnné volba si uložíme stisknutý znak jako char. Protože rozsah znaků neotestujeme s dosavadními znalostmi tak jednoduše jako rozsah čísel, pomůžeme si jiným způsobem. Připravíme si proměnnou platnaVolba typu bool, kterou nastavíme na true (budeme předpokládat, že je volba správná). Konstrukce switch zůstane podobná, jen čísla dáme nyní do apostrofů, protože se nyní jedná o jednotlivé znaky. Přidáme možnost default:, která v případě jiné hodnoty než jmenovaných nastaví námi připravenou proměnnou platnaVolba na false. Potom není nic jednoduššího, než tuto proměnnou otestovat. Vyzkoušejte si to, program se používá nyní pohodlněji.

Nakonec upravíme ještě výzvu k pokračování, zadávat budeme opět char A/N, budeme tolerovat různou velikost písmen a reagovat na špatné zadání. Opět použijeme switch, naši proměnnou pokracovat změníme na typ bool. Kód je asi zbytečné více popisovat, za zmínku stojí pouze kombo Console.ReadKey().KeyChar.ToString().ToLower(), které načte znak z konzole a vrátí ho jako string malými písmeny.

Protože se jedná o větší kus kódu, použijeme tzv. komentáře. Ty s píší pomocí dvoulomítka (dvou lomítek za sebou). Jsou to informace pro programátora, kompilátor si jich nevšímá.

Console.WriteLine("Vítejte v kalkulačce");
bool pokracovat = true;
while (pokracovat)
{
    // načtení čísel
    Console.WriteLine("Zadejte první číslo:");
    float a;
    while (!float.TryParse(Console.ReadLine(), out a))
        Console.WriteLine("Neplatné číslo, zadejte prosím znovu:");
    Console.WriteLine("Zadejte druhé číslo:");
    float b;
    while (!float.TryParse(Console.ReadLine(), out b))
        Console.WriteLine("Neplatné číslo, zadejte prosím znovu:");
    // volba operace a výpočet
    Console.WriteLine("Zvolte si operaci:");
    Console.WriteLine("1 - sčítání");
    Console.WriteLine("2 - odčítání");
    Console.WriteLine("3 - násobení");
    Console.WriteLine("4 - dělení");
    char volba = Console.ReadKey().KeyChar;
    Console.WriteLine();
    float vysledek = 0;
    bool platnaVolba = true;
    switch (volba)
    {
        case '1':
            vysledek = a + b;
            break;
        case '2':
            vysledek = a - b;
            break;
        case '3':
            vysledek = a * b;
            break;
        case '4':
            vysledek = a / b;
            break;
        default:
            platnaVolba = false;
            break;
    }
    if (platnaVolba)
        Console.WriteLine("Výsledek: {0}", vysledek);
    else
        Console.WriteLine("Neplatná volba");
    Console.WriteLine("Přejete si zadat další příklad? [a/n]");
    // dotaz na pokračování
    platnaVolba = false;
    while (!platnaVolba)
    {
        switch (Console.ReadKey().KeyChar.ToString().ToLower())
        {
            case "a":
                pokracovat = true;
                platnaVolba = true;
            break;
            case "n":
                pokracovat = false;
                platnaVolba = true;
            break;
            default:
                Console.WriteLine("Neplatná volba, zadejte prosím a/n");
            break;
        }
    }
    Console.WriteLine();
}

Konzolová aplikace
Zadejte první číslo:
cislo
Neplatné číslo, zadejte prosím znovu:
13
Zadejte druhé číslo:
22
Zvolte si operaci:
1 - sčítání
2 - odčítání
3 - násobení
4 - dělení
3
Výsledek: 286
Přejete si zadat další příklad? [a/n]
h
Neplatná volba, zadejte prosím a/n

Gratuluji, právě jste vytvořili svůj první blbovzdorný program :) Kód se nám trochu zkomplikoval, snad jste to všechno pochytili. Někdy v budoucnu to třeba napravíme a rozdělíme ho do přehledných metod, pro tuto sekci však považujme kalkulačku za hotovou, možná by se do ní jen mohlo přidat více matematických funkcí, na ty se v C# kurzu také zaměříme.

Čeká nás pole a pokročilá práce s řetězci. Potom to bude z konstrukcí v této sekci vše, blížíme se ke konci :)

V příští lekci, Pole v C# .NET, se opět ponoříme do nových konstrukcí a představíme si pole.


 

Stáhnout

Staženo 837x (24.01 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

Předchozí článek
Řešené úlohy k 6. lekci C# .NET
Všechny články v sekci
Základní konstrukce jazyka C# .NET
Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
62 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn university Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (12)

 

 

Komentáře
Zobrazit starší komentáře (114)

Avatar
Honzis
Člen
Avatar
Honzis:1.5.2019 14:24

To byla fakt blesková odpověď, díky :-) No to tvoje řešení mi přijde logičtější, protože jak jsi řekl, jednou klávesou mohu zadat pouze jeden znak a datový typ char je pro tento účel určený. Převádět to tedy ještě z charu na string mi přijde trošku nelogické, když string je určený pro delší řetězec, než jeden znak, ale to už se v tom asi pitvám až moc, na výsledek to očividně nemá vliv.

 
Odpovědět
1.5.2019 14:24
Avatar
Dereq
Člen
Avatar
Dereq:8. ledna 23:19

Proč tam nefunguje příkaz WriteLine, ale napíše se to do stejného řádku k zadanému znaku?
Měl by to někdo opravit na:

default:
       Console.WriteLine();
       Console.WriteLine("Neplatná volba, zadejte prosím a/n");
       break;
 
Odpovědět
8. ledna 23:19
Avatar
Marek Vajčner:7. března 13:37

Díky za další stručnou a jasnou lekci. No jasnou. Uvidíme posléze v testech. ;-)

 
Odpovědět
7. března 13:37
Avatar
Petr Staněk
Člen
Avatar
Petr Staněk:7. března 14:04

Můžu se optat proč je u podmínky na ukončení nebo opakování programu u obou podmínek pro "platnavolba" hodnota nastavena na true? Když změním na false tak po zadaní a potvrzení entrem neprovede žádnou akci a musím entrem znovu potvrdit, což vrací, že jsme zadali neplatnou volbu.

 
Odpovědět
7. března 14:04
Avatar
Odpovídá na Petr Staněk
Marek Vajčner:7. března 14:53

Protože program v tom momentě vyžaduje zmáčknutí buď klávesy "a" pro pokračování nebo klávesy "n" pro ukončení. Obě možnosti jsou korektní, tedy platné.
Proto jsou obě podmínky - platnaVolba = true. Jakákoli jiná klávesa je nekorektní a vypíše se hláška "Neplatná volba, zadejte a/n ".

 
Odpovědět
7. března 14:53
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Petr Staněk
Člen
Avatar
Odpovídá na Marek Vajčner
Petr Staněk:7. března 15:09

Už jsem na to došel. Jednalo se o to, že pokud byla zadána platnaVolba = false, tak se cykl while stále opakoval. Program tedy došel jakoby o řádek níže while cyklu, ale neměl nic zadané jako předtím a proto musela být stisknuta jiná klávesa. S tím již začal fungovat switch a program šel dále. False tedy u proměnné znemožňoval opustit cyklus.

 
Odpovědět
7. března 15:09
Avatar
David Holohlavský:8. března 15:46

Díky za článek. ;-)

 
Odpovědět
8. března 15:46
Avatar
Vlkodlak90
Člen
Avatar
Vlkodlak90:2. dubna 22:46

Ja som sa trošku pobavil a mám z toho radosť ošetril som delenie nulou a pridal som medzery. :)
Môj kod

Editováno 2. dubna 22:48
 
Odpovědět
2. dubna 22:46
Avatar
Jiří Rajt
Člen
Avatar
Jiří Rajt:7. dubna 13:54

No, zas taková oddychovka to tedy nebyla. :-) Je pro mě těžký zapamatovat si věci, jejichž vysvětlení se odloží na později. Každopádně jsem si musel v jednom případě vypomoct příkazem goto, který mi utkvěl v hlavě ještě z dob, kdy jsem jako malej kluk zkoušel programovat v basicu. Bohužel mi to totiž házelo chyby u proměnné "operace".

Zdroják: https://www.itnetwork.cz/…lighter/1302

 
Odpovědět
7. dubna 13:54
Avatar
Andrea K.
Člen
Avatar
Andrea K.:28. srpna 20:03

paradni! :D kdyz je nekdo hracicka, tak mu to chvili trva :) ale zasa nedelime 0 a trosku jinak jsem si to rozhodila. Moc se mi libi, ze v celem prikladu se vyuziva vse co se probralo v predeslich lekcich. tesim se na dalsi ;-)

 
Odpovědět
28. srpna 20:03
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 124. Zobrazit vše