Diskuze: If, else a switch

C# .NET .NET (C# a Visual Basic) If, else a switch American English version English version

Avatar
BeriCud
Neregistrovaný
Avatar
BeriCud:

Ahoj už jsem se jednou na jednu věc ptal a moc děkuji za vysvětlení a Vaši pomoc. Mám ještě jednu otázku v předposledním programu nazvaném kalkulačka se používá if a else. Rozumím jak to funguje jen nechápu výhodu tohoto zápisu. Myslím konkrétně tady toto:
Console.Write­Line("Zvolte si operaci:");
Console.Write­Line("1 - sčítání");
Console.Write­Line("2 - odčítání");
Console.Write­Line("3 - násobení");
Console.Write­Line("4 - dělení");
int volba = int.Parse(Con­sole.ReadLine());
float vysledek = 0;
if (volba == 1)
vysledek = a + b;
else
if (volba == 2)
vysledek = a - b;
else
if (volba == 3)
vysledek = a * b;
else
if (volba == 4)
vysledek = a / b;
Jdeš mi o to zvýrazněné else jakou to má výhodu je tam dávat když program funguje stejně i bez nich a ikdyž tam jsou musí se zjistit jestli náhodou je podmínka splněna tak že if tam musí a else bych moch vynechat a kod by se zkrátil.

 
Odpovědět 10.2.2013 18:23
Avatar
matesax
Redaktor
Avatar
Odpovídá na BeriCud
matesax:

Coo - pokud je bolean vyhodnocen v if jako true, provede se if část, jinak else. Jestli else potřebuješ je přeci na tobě... else se už vůbec nehodnotí - je to prostě zbytek...

 
Nahoru Odpovědět 10.2.2013 18:35
Avatar
Зайчик
Člen
Avatar
Odpovídá na BeriCud
Зайчик:

else tam dávat vůbec nemusíš být tebou tak to udělám do switche, tohle je zrůdovina.

switch(vobla)
{
    case 1: vysledek = a + b;
    break;
    case 2: vysledek = a - b;
    break;
    // a tak dále..
}
Nahoru Odpovědět  +1 10.2.2013 18:48
Коммунизм для нашего будущего!
Avatar
Odpovídá na BeriCud
Luboš Běhounek (Satik):

V tomhle případě rozdíl mezi použitím a nepoužitím else je ten, že s else je to rychlejší.

Celá else větev se vůbec neprovádí, pokud byla podmínka splněna.

Tvůj kód s else (zapsaný trochu přehledněji, aby to bylo lépe vidět):

if (volba == 1)
  vysledek = a + b;
else
  if (volba == 2)
    vysledek = a - b;
  else
    if (volba == 3)
      vysledek = a * b;
    else
      if (volba == 4)
        vysledek = a / b;

Ale jak psal Зайчик , na tohle je lepší switch, který kompilátor dokáže efektivně zoptimalizovat.

Editováno 10.2.2013 19:36
Nahoru Odpovědět 10.2.2013 19:35
:)
Avatar
matesax
Redaktor
Avatar
Odpovídá na Зайчик
matesax:

Já bych to udělal takto:

Action<int, int>[] operations = new Action<int, int>[]
{
    delegate (int a, int b) { vysledek = a + b; },
    delegate (int a, int b) { vysledek = a - b; },
    delegate (int a, int b) { vysledek = a * b; },
    delegate (int a, int b) { vysledek = a / b; }
};

...

Action[volba](a, b);
Editováno 10.2.2013 19:40
 
Nahoru Odpovědět 10.2.2013 19:37
Avatar
lcet.m
Člen
Avatar
Odpovídá na matesax
lcet.m:

To bys to udělal blbě, no.

 
Nahoru Odpovědět 10.2.2013 19:40
Avatar
matesax
Redaktor
Avatar
Odpovídá na lcet.m
matesax:

Ani ne... :) (Nemám čas - spěchám...)

Místo:

Action[volba](a, b);

Má být samozřejmě:

operations[volba](a, b);
Editováno 10.2.2013 19:42
 
Nahoru Odpovědět 10.2.2013 19:41
Avatar
Зайчик
Člen
Avatar
Odpovídá na matesax
Зайчик:

nevím proč by to mělo být špatně, ale je snad jasný že nejednodušší způsob je ten nejlepší a v tomhle případě to bude ten můj si myslím

Nahoru Odpovědět 10.2.2013 19:43
Коммунизм для нашего будущего!
Avatar
Odpovídá na matesax
Luboš Běhounek (Satik):

Až budu potřeboval bagrem vyhrabat díru pro zasazení petrželky, tak se ti ozvu, jo? :)

Nahoru Odpovědět  +1 10.2.2013 19:48
:)
Avatar
lcet.m
Člen
Avatar
lcet.m:

Samozřejmě že Winitrixův způsob je správně, zvlášť jako rada začátečníkovi. Pokud si někdo chce zafrajeřit a použít místo normálního switche seznam odkazů na funkci, měl by aspoň vědět, jak se to píše.

Matesi, až budou ty tvoje paskvily aspoň fungovat, co kdybys zkusil napsat nějakej obfuscator? Ty jseš na to jak zrozenej!

 
Nahoru Odpovědět  +1 10.2.2013 19:50
Avatar
lcet.m
Člen
Avatar
Odpovídá na matesax
lcet.m:

A místo Action<,> má být samozřejmě Func<,,> a samozřejmě je to celý uplně zbytečný.

 
Nahoru Odpovědět  +1 10.2.2013 19:52
Avatar
matesax
Redaktor
Avatar
Odpovídá na lcet.m
matesax:

Kdepak - jede mi to... :) (A může tam být obojí.)

Sorry, že nevětvím ihned, jakmile mne jiného nic nenapadne. switch je obecně hrozný... (a přehlednost to zase tak moc nepřebíjí)

 
Nahoru Odpovědět 10.2.2013 20:06
Avatar
lcet.m
Člen
Avatar
Odpovídá na matesax
lcet.m:

Hm. Teď možná jo. Protože jsi to zeditoval. Původně tam bylo tohle:

Action<int, int>[] operations = new Action<int, int>[]
{
    delegate (int a, int b) { a + b },
    delegate (int a, int b) { a - b },
    delegate (int a, int b) { a * b },
    delegate (int a, int b) { a / b }
};
 
Nahoru Odpovědět 11.2.2013 8:59
Avatar
lcet.m
Člen
Avatar
Odpovídá na matesax
lcet.m:

PROČ je zase switch obecně hrozný? Nefunguje? Je míň přehledný než ten tvůj seznam delegátů, který jsi ani nedokázal napoprvé napsat správně? Je někomu, kdo jde číst článek o větvení, k něčemu příklad na vyhnutí se větvení? Když tak nerad větvíš, tohle není tvůj kód?

function MapMenu(ul) {

    if (!ul.hasChildNodes())
        return;

    for (var index in ul.childNodes) {

        if (!ul.childNodes[index].tagName)
            continue;

        if (ul.childNodes[index].tagName.toLowerCase() == 'li') {

            if (ul.childNodes[index].hasChildNodes())

                for (var c in ul.childNodes[index].childNodes) {

                    if (!ul.childNodes[index].childNodes[c].tagName)
                        continue;

                    if (ul.childNodes[index].childNodes[c].tagName.toLowerCase() == 'ul') {

                        $(ul.childNodes[index]).hover(function () {

                            OpenSubMenu(this);
                        }, function () {

                            HideMenu();
                        });

                        MapMenu(ul.childNodes[index].childNodes[c]);
                    }
                }
        }
    }
}
 
Nahoru Odpovědět 11.2.2013 9:09
Avatar
matesax
Redaktor
Avatar
Odpovídá na lcet.m
matesax:

Hmm - to s tím hodně souvisí... Kde vidíš switch? Přečti si o něm něco...

 
Nahoru Odpovědět 11.2.2013 9:23
Avatar
lcet.m
Člen
Avatar
Odpovídá na lcet.m
lcet.m:

"switch je obecně hrozný" jsi napsal ty. Já se ptám proč.

 
Nahoru Odpovědět 11.2.2013 9:27
Avatar
David Čápka
Tým ITnetwork
Avatar
David Čápka:

Složitější switche mohou být opravdu na obtíž a dají se nahradit lepšími konstrukcemi, nicméně v aktuálním případě je switch naprosto v pořádku. Nevím, proč musí matesax stále radit své hashmapy a delegáty někomu kdo má za sebou prvních 5 lekcí jazyka. Matěji, to ti opravdu nedojde, že u 5. lekce kde se vysvětluje jak funguje IF, není vhodné vytahovat delegáty? Jsem z tvého chování na devbooku již velmi unaven, řešili jsme to spolu již několikrát a je to stále dokola. Pokud chceš na devbooku dále působit, naposledy tě prosím, abys přestal psát začátečníkům nesmysly. Děkuji.

Editováno 11.2.2013 9:46
Nahoru Odpovědět  +1 11.2.2013 9:45
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Odpovídá na matesax
Lukáš Hruda (Luckin):

Co je na switchi hroznýho? Pokud jde použít, tak je mnohem přehlednější než if else větvení. Odkazy na funkce/metody bych použil pokud by to větvení bylo zbytečně dlouhý a ty větve byly delší. Tady jsou 4 větve a každá na jeden řádek, to je trochu kanon na vrabce.

 
Nahoru Odpovědět  +1 11.2.2013 9:46
Avatar
Odpovídá na David Čápka
Luboš Běhounek (Satik):

Složitější switche mohou být na obtíž?

A jak bys tedy třeba jinak (přehledněji) napsal switch pro třeba 150 hodnot?

Nahoru Odpovědět 11.2.2013 9:51
:)
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Luboš Běhounek (Satik)
David Čápka:

Nesprávné použití switche je třeba toto:

switch (hodnota)
{
   case 1:
     return "jedna";
   break;
   case 2:
     return "dva";
     break;
   ...
}

Toto v různých formách opravdu často vídám, lepší řešení je toto:

string[] hodnoty = {"jedna", "dva", ...};
return hodnoty[hodnota - 1];

Switch můžeme nahradit dále zmíněnými delegáty. Pokud v programu evidujeme 100 vzorců, je určitě dobrý nápad to tak udělat, viz. ta Matějova příšernost, která se v dané situace ale vůbec nehodí.

Pokud mámě někde 500ti řádkový switch, je vhodné kód jednotlivých větví rozdělit do metod, vznikne pak toto:

switch (hodnota)
{
  case 1:
    jedna();
    break;
  case 2:
    dva();
    break;
  ...
}

Pokud se i toto zvrhne, je lepší použít předávání tříd, vypůjčím si ukázku ze Stack Overflow (http://stackoverflow.com/…ents-bad-oop)

switch (eFoo)
{
case Foo.This:
  eatThis();
  break;
case Foo.That:
  eatThat();
  break;
}

switch (eFoo)
{
case Foo.This:
  drinkThis();
  break;
case Foo.That:
  drinkThat();
  break;
}

Refaktorujeme na:

IAbstract
{
  void eat();
  void drink();
}

class This : IAbstract
{
  void eat() { ... }
  void drink() { ... }
}

class That : IAbstract
{
  void eat() { ... }
  void drink() { ... }
}

Abychom si rozuměli, neříkám, že je switch špatný. Do určité úrovně je naprosto v pořádku, ale jakmile se nám to moc rozleze, měli bychom zvážit refaktorování kódu na něco vhodnějšího. Tak je to přeci s každou programátorskou konstrukcí.

Editováno 11.2.2013 10:02
Nahoru Odpovědět 11.2.2013 10:02
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Odpovídá na David Čápka
Luboš Běhounek (Satik):

Co jsi tu ukázal moc nesouvisí se složitostí switche, ale s použitím switche ve špatné situaci.

Pokud máš switch, který zpracovává třeba nějakou multiplayerovou herní logiku (kde těch hodnot může být třeba 500 a každá se zpracovává nějak odlišně), tak je pořád switch nejvhodnější, i když je rozlezlý (samozřejmě je vhodné nevykonávat kód přímo v tom switchi, ale volat z něj jednotlivé metody, to jsi tam zmiňoval).

Nahoru Odpovědět 11.2.2013 10:19
:)
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Luboš Běhounek (Satik)
David Čápka:

Mám za to, že jednoduchý switch nevadí nikdy. Až se zvyšující se složitostí má smysl vymýšlet co s tím, tedy lidově řečeno "až v tom začne být bordel".

Co konkrétně máš v jednotlivých casech v tom switchi ze hry?

Nahoru Odpovědět 11.2.2013 10:24
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Odpovídá na David Čápka
Luboš Běhounek (Satik):

V té strategii, co teď dělám, žádný velký switch nemám, ale v předchozím působišti jsme měli switch, kde bylo asi 170 case v největším switchi, tady je ukázka nějakého už většího switche (ale jsou tam i mnohem větší, ale vypadají podobně):

http://pastebin.com/isQVnUT6

Složitější věci mají vlastní funkci, jednoduché na pár řádků se tady řeší přímo ve switchi.

Nahoru Odpovědět 11.2.2013 10:41
:)
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Luboš Běhounek (Satik)
David Čápka:

Tohle se obecně řeší přes rozhraní, uděláš si interface IEvent s metodou Execute() a pak třídu pro každou událost, switch pak není potřeba, na eventu co přijde rovnou zavoláš Execute a je ti jedno jakého je typu.

Vždycky to ale tak nejde, záleží na tom, odkud ti ty eventy lezou, předpokládám, pokud jsou to třeba stringy ze sítě, tak to bez switche asi nepůjde. Tento případ jsem viděl řešit přes slovník, kde byl klíč string a hodnota delegát, takový slovník eventů byl velmi přehledný. Delegátu se dá vyhnout tak, že předáme instanci co implementuje rozhraní IEvent. Viděl jsem to řešit také přes reflexi, kde měla obslužná metoda ten samý název jako událost, to ale asi trochu degraduje výkon.

Editováno 11.2.2013 10:53
Nahoru Odpovědět 11.2.2013 10:50
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
lcet.m
Člen
Avatar
lcet.m:

Na něco podobného jsem tu reflexi použil, obsluhující metody musí být označeny atributem, podle kterého se přiřadí metoda k signálu. Výkon je ok, protože se na začátku naplní Dictionary<string, MethodInfo>

 
Nahoru Odpovědět 11.2.2013 11:32
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na lcet.m
David Čápka:

Nojo, to mi nedošlo a atributy to v C# ještě celé zjednoduší :)

Nahoru Odpovědět 11.2.2013 11:34
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Odpovídá na David Čápka
Luboš Běhounek (Satik):

Uh, s těma delegátama by to bylo složitější, protože některé funkce parametrů mají víc a některé nemají třeba žádný.

Šlo by to samozřejmě třeba obejít tím, že by se všude posílal jako parametr typ Object a ten se ignoroval (pokud žádný parametr není) nebo v případě více parametrů by v něm bylo uloženo pole objektů, ale než vymýšlet tyhle kontrukce, tak radši použiju switch, i pro nově příchozího člověka ten kód se switchem bude mnohem přehlednější...

Nahoru Odpovědět 11.2.2013 11:42
:)
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Luboš Běhounek (Satik)
David Čápka:

Přeci nebudeme vynalézat kolo, patternů co řeší parametry událostí je mnoho, sám C# předává potomky EventArguments. Uplně nejjednodušeji tam můžeš dát pole Objectů. Nebo použít zmíněnou reflexi.

Myslím že pro nově příchozího člověka ten kód co jsi poslal moc přehledný nebude :)

Nahoru Odpovědět 11.2.2013 11:53
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
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 28 zpráv z 28.