Válí se ti projekty v šuplíku? Dostaň je mezi lidi a získej cool tričko a body na profi IT kurzy v soutěži ITnetwork summer 2017!
Přidej si svou IT školu do profilu a najdi spolužáky zde na síti :)

7. díl - Ošetření uživatelských vstupů

C# .NET Základní konstrukce Ošetření uživatelských vstupů American English version English version

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Cykly v C#, jsme se zabývali cykly. 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í 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.

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 "!", tedy dokud 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á). 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.ReadKe­y().KeyChar.ToS­tring().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 seriálu také zaměříme.

V příští lekci, Pole v C#, se opět ponoříme do nových konstrukcí. Č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 :)


 

Stáhnout

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

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
36 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 College Autor se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Miniatura
Předchozí článek
Cykly v C#
Miniatura
Všechny články v sekci
Základní konstrukce jazyka C#
Miniatura
Následující článek
Pole v C#
Aktivity (6)

 

 

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

Avatar
David Vavrečka:11. května 19:15

Ahoj, chci se jen zeptat k čemu přesně slouží ToString(), nikde v serialu jsem to tady, ani v předchozích lekcích nenašel. Díky :-)

 
Odpovědět 11. května 19:15
Avatar
gcx11
Redaktor
Avatar
Odpovídá na David Vavrečka
gcx11:11. května 19:35

Obecně to převede cokoliv na řetěžec. V tomto případě se převede znak (char) na řetězec (string), jinak bys v tom switchi nemohl naráz porovnávat velké a malé písmeno.

 
Odpovědět 11. května 19:35
Avatar
David Vavrečka:11. května 20:27

Aha. Díky. :-)

 
Odpovědět 11. května 20:27
Avatar
Martin Kostelka:3. června 15:24

Jen malá připomínka, jsem sice začátečník, ale když zvolíte čísla a náhodou se překliknete u operace, tak podle toho kódu místo aby požádal znovu o zadání početní operace, tak se to zeptá pouze."přeje te si zadat další příklad" vím že to asi bude jen malichernost ale znovu projíždět zadávání čísel nebylo by lepší udělat stejně kód jako u chyby při zadávání čísel?Vím že mi předtím někdo radil s cyklem ale goto mi příjde pohodlnější

 
Odpovědět 3. června 15:24
Avatar
gcx11
Redaktor
Avatar
Odpovídá na Martin Kostelka
gcx11:3. června 16:18

Píšou se stále složitější a větší programy, proto se i paradigmata programování vyvíjejí, aby se dal dobře takový větší program udržovat.

Na takto jednoduchou kalkulačku se dá použít goto, ale pokud tam přidáš další funkcionalitu, tak se v tom po chvilce nevyznáš, protože budeš zkoumat, proč se někde skončilo o dalších 200 řádek jinam a co tam program vlastně dělá.

Proto se později začaly používat funkce, které mají něco provést, ale Tebe už pak nemusí zajímat, co to dělá vnitřně, pokud to nemá nějaký nečekaný vedlejší efekt. Například funkce, co načte číslo:

float getNumber(String prompt, String errorMessage){
        float number;
        Console.WriteLine(prompt);
        while (!float.TryParse(Console.ReadLine(), out number))
                Console.WriteLine(errorMessage);
        return number;
}

Použití:

float a = getNumber("Zadejte první číslo:", "Neplatné číslo, zadejte prosím znovu:");
float b = getNumber("Zadejte druhé číslo:", "Neplatné číslo, zadejte prosím znovu:")

Čímž zredukuješ kód, který tam je dvakrát. Tím pádem, pokud je v tom načítání čísel chyba, tak jí stačí opravit jenom na jednom místě v programu.

A jakmile ani samotné funkce nestačily, tak se vyvinulo objektově orientované programování, které sdružuje stejná data do objektů. Například informace o člověku (jméno, příjmení, věk) a pak se s tím mnohem lépe pracuje, ale k tomu se dostaneš časem.

class Person{
      string firstName;
      string lastName;
      int age;
}

Goto bys měl maximálně použít, když potřebuješ ihned vyskočit z nějakého hodně zanořeného cyklu anebo když potřebuješ přeskočit ve switchi z jednoho case do dalšího. Lepší je použít while cyklus, stejně se to přeloží do goto, ale program bude přehlědnější.

 
Odpovědět 3. června 16:18
Avatar
Odpovídá na gcx11
Martin Kostelka:5. června 9:09

Mno já mám goto právě s if a dostane se to na goto pouze pokud podmínka neplatí. a u zadání čísel mám while ale u příkladu nahoře se podívej když máš početní operaci (+,-,*,/) tak po stisknutí špatné klávesnie se musí zadat nový příklad jak by to s tím float teda vypadalo jedině narvat to do else o tento sekci kódu my jde dal jsem to zatím s tím goto. stačí jestli bys mi poslal pouze stím else a dál abych to pochopil asi jsem trochu tupý ale ze školy jsem nějakej ten pátek tak jsem se odvikl něco učit :-)
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:
neplatnaVolba = false;
break;
}
if (neplatnaVolba)
Console.Write­Line("Výsledek: {0}", vysledek);
else
goto zadání;

Editováno 5. června 9:10
 
Odpovědět 5. června 9:09
Avatar
gcx11
Redaktor
Avatar
Odpovídá na Martin Kostelka
gcx11:5. června 11:42
bool platnaVolba = false;
float vysledek = 0;
while (!platnaVolba){
        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();
        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;
        }
}
 
Odpovědět 5. června 11:42
Avatar
Odpovídá na gcx11
Martin Kostelka:5. června 15:40

mno jo ale tvoje řešení neřeší, že když zmačknem špatné číslo pro zadání výpočetní operace aby to nabýdlo opět početní operaci,v tvém kódu nabýdne to "přeje te si zadat další příklad?" pokud dáš "a" musíš zadat opět čísla možná jsme si jen špatně porozumněli nešlo by se nějako spojit třeba na TS nebo tak (skype nemám) něco v online režimu stačí i nějakej chat

 
Odpovědět 5. června 15:40
Avatar
gcx11
Redaktor
Avatar
Odpovídá na Martin Kostelka
gcx11:7. června 14:23

Musíš si upravit i zbytek, aby to pak fungovalo, když už teď máš jistotu, že budeš mít dobře volbu operace.

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();
                bool platnaVolba = false;
                float vysledek = 0;
                while (!platnaVolba)
                {
                    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();
                    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;
                            Console.WriteLine("Neplatná volba");
                            break;
                    }
                }
                Console.WriteLine("Výsledek: {0}", vysledek);
                // dotaz na pokračování
                platnaVolba = false;
                Console.WriteLine("Přejete si zadat další příklad? [a/n]");
                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();
            }
 
Odpovědět  +1 7. června 14:23
Avatar
Martin Kostelka:19. června 11:00

ježiši už vím proč mi ta cikle předtím nefungovala nemněl jsem tam } ve volbě oprerace na konci jsem tam mněl 1 a musej tam bejt dvě takže jsem to zkoušel předtím dobře jen jsem zapomněl složenou závorku taková prkotina a dokáže pozlobit XD jinak omlouvám se mněl jsem hodně práce dítě na cestě tak jsme předělávali chodbu tak jsem nemněl čas :-)

 
Odpovědět 19. června 11:00
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 76. Zobrazit vše