it-swarm-eu.dev

Více případů v příkazu switch

Existuje způsob, jak propadnout několika případovým prohlášením, aniž byste opakovaně uváděli case value:?

Vím, že to funguje:

switch (value)
{
   case 1:
   case 2:
   case 3:
      //do some stuff
      break;
   case 4:
   case 5:
   case 6:
      //do some different stuff
      break;
   default:
       //default stuff
      break;
}

ale rád bych něco takového udělal:

switch (value)
{
   case 1,2,3:
      //Do Something
      break;
   case 4,5,6:
      //Do Something
      break;
   default:
      //Do the Default
      break;
}

Mám na mysli tuto syntaxi z jiného jazyka, nebo mi něco chybí?

517
theo

Pro druhou metodu, kterou jste zmínili, není v C++ ani C # žádná syntaxe.

Na první metodě není nic špatného. Pokud však máte velmi velké rozsahy, stačí použít řadu příkazů.

282
Brian R. Bondy

Myslím, že to už bylo zodpovězeno. Domnívám se však, že můžete stále kombinovat obě možnosti syntakticky lepším způsobem:

switch (value)
{
case 1: case 2: case 3:          
    // Do Something
    break;
case 4: case 5: case 6: 
    // Do Something
    break;
default:
    // Do Something
    break;
}
640

Tato syntaxe je z příkazu Visual Basic Select ... :

Dim number As Integer = 8
Select Case number
    Case 1 To 5
        Debug.WriteLine("Between 1 and 5, inclusive")
        ' The following is the only Case clause that evaluates to True.
    Case 6, 7, 8
        Debug.WriteLine("Between 6 and 8, inclusive")
    Case Is < 1
        Debug.WriteLine("Equal to 9 or 10")
    Case Else
        Debug.WriteLine("Not between 1 and 10, inclusive")
End Select

Tuto syntaxi nelze použít v jazyce C #. Místo toho musíte použít syntaxi z prvního příkladu.

65
Neal

Trochu pozdě na původní otázku, ale tuto odpověď odesílám v naději, že někdo používá novější verzi ( C # 7 - ve výchozím nastavení k dispozici ve Visual Studio 2017/.NET Framework 4.6.2 ) , bude to užitečné.

V C # 7 je nyní možné přepínání na základě rozsahu pomocí příkazu switch a pomoci s problémem OP.

Příklad:

int i = 5;

switch (i)
{
    case int n when (n >= 7):
        Console.WriteLine($"I am 7 or above: {n}");
        break;

    case int n when (n >= 4 && n <= 6 ):
        Console.WriteLine($"I am between 4 and 6: {n}");
        break;

    case int n when (n <= 3):
        Console.WriteLine($"I am 3 or less: {n}");
        break;
}

// Output: I am between 4 and 6: 5

Poznámky:

  • Závorky ( a ) se v podmínce when nevyžadují, ale v tomto příkladu se používají ke zvýraznění porovnání.
  • var lze také použít místo int. Například: case var n when n >= 7:.
47
Steve Gomez

Nový řádek, který vám umožní:

case 1: case 2: case 3:
   break;

ale myslím, že ten špatný styl.

31
Allan Wind

.NET Framework 3.5 má rozsahy:

Enumerable.Range from MSDN

můžete jej použít s "obsahuje" a IF prohlášení, protože jako někdo řekl, že příkaz SWITCH používá "==" operátor.

Zde je příklad:

int c = 2;
if(Enumerable.Range(0,10).Contains(c))
    DoThing();
else if(Enumerable.Range(11,20).Contains(c))
    DoAnotherThing();

Ale myslím, že můžeme mít více zábavy: protože nebudete potřebovat návratové hodnoty a tato akce nebude mít parametry, můžete snadno použít akce!

public static void MySwitchWithEnumerable(int switchcase, int startNumber, int endNumber, Action action)
{
    if(Enumerable.Range(startNumber, endNumber).Contains(switchcase))
        action();
}

Starý příklad s touto novou metodou:

MySwitchWithEnumerable(c, 0, 10, DoThing);
MySwitchWithEnumerable(c, 10, 20, DoAnotherThing);

Protože předáváte akce, ne hodnoty, měli byste vynechat závorky, je to velmi důležité. Pokud potřebujete funkci s argumenty, stačí změnit typ Action na Action<ParameterType>. Pokud potřebujete vrátit hodnoty, použijte Func<ParameterType, ReturnType>.

V C # 3.0 není jednoduché Částečná aplikace pro zapouzdření skutečnosti, že parametr case je stejný, ale vytvoříte malou pomocnou metodu (bit verbose, tho).

public static void MySwitchWithEnumerable(int startNumber, int endNumber, Action action){ 
    MySwitchWithEnumerable(3, startNumber, endNumber, action); 
}

Zde je příklad, jak jsou nové funkční importované výrazy IMHO silnější a elegantnější než staré imperativní.

18
Luca Molteni

@ Jennifer Owens: máte pravdu, že níže uvedený kód nebude fungovat:

case 1 | 3 | 5:
//not working do something

Jediný způsob, jak toho dosáhnout, je:

case 1: case 2: case 3:
// do something
break;

Kód, který hledáte, pracuje na vizuálním základu, kde můžete snadno umístit rozsahy ... v žádné volbě přepínače nebo pokud jinak blokujete vhodné, navrhl bych, aby ve velmi extrémním bodě vytvořil .dll s vizuálním základem a importem zpět k vašemu projektu c #.

Poznámka: přepínač ekvivalentní ve vizuálním základu je volba case.

8
none

Další možností by bylo použití rutiny. Pokud všechny případy 1-3 provedou stejnou logiku, pak tuto logiku zabalíme do rutiny a zavoláme ji pro každý případ. Vím, že to vlastně nezbavuje případové výkazy, ale implementuje dobrý styl a udržuje údržbu na minimu .....

[Upravit] Přidána alternativní implementace odpovídající původní otázce ... [/ Edit]

switch (x)
{
   case 1:
      DoSomething();
      break;
   case 2:
      DoSomething();
      break;
   case 3:
      DoSomething();
      break;
   ...
}

private void DoSomething()
{
   ...
}

Alt

switch (x)
{
   case 1:
   case 2:
   case 3:
      DoSomething();
      break;
   ...
}

private void DoSomething()
{
   ...
}
7
Dr8k

gcc implementuje rozšíření do jazyka C pro podporu sekvenčních rozsahů:

switch (value)
{
   case 1...3:
      //Do Something
      break;
   case 4...6:
      //Do Something
      break;
   default:
      //Do the Default
      break;
}

Upravit: Prostě si všiml C # tag na otázku, tak pravděpodobně gcc odpověď nepomůže.

5
DGentry

Zde je kompletní řešení C # 7 ...

switch (value)
{
   case var s when new[] { 1,2,3 }.Contains(s):
      //Do Something
      break;
   case var s when new[] { 4,5,6 }.Contains(s):
      //Do Something
      break;
   default:
      //Do the Default
      break;
}

Pracuje také s řetězci ...

switch (mystring)
{
   case var s when new[] { "Alpha","Beta","Gamma" }.Contains(s):
      //Do Something
      break;
...
}
5
Carter Medlin

Jedním z méně známých aspektů přepínače switch in C # je, že se spoléhá na operator = a protože může být přepsáno, můžete mít něco takového:


string s = foo();

switch (s) {
  case "abc": /*...*/ break;
  case "def": /*...*/ break;
}
5

Vlastně nemám rád ani příkaz GOTO, ale je to v oficiálních materiálech MS, zde jsou všechny povolené syntaxe.

Pokud je dosažitelný koncový bod seznamu výpisů přepínací sekce, dojde k chybě kompilace. Toto je znáno jak “ne propadnout” pravidlo. Příklad

switch (i) {
case 0:
   CaseZero();
   break;
case 1:
   CaseOne();
   break;
default:
   CaseOthers();
   break;
}

je platný, protože žádný přepínací úsek nemá dosažitelný koncový bod. Na rozdíl od C a C++ není provedení přepínací sekce dovoleno "propadnout" do další sekce přepínače a do příkladu

switch (i) {
case 0:
   CaseZero();
case 1:
   CaseZeroOrOne();
default:
   CaseAny();
}

výsledkem je chyba kompilace. Pokud má po provedení sekce přepínače následovat provedení jiné sekce přepínače, musí být použit explicitní případ goto nebo výchozí příkaz goto:

switch (i) {
case 0:
   CaseZero();
   goto case 1;
case 1:
   CaseZeroOrOne();
   goto default;
default:
   CaseAny();
   break;
}

V přepínači je povoleno více štítků. Příklad

switch (i) {
case 0:
   CaseZero();
   break;
case 1:
   CaseOne();
   break;
case 2:
default:
   CaseTwo();
   break;
}

V tomto konkrétním případě se domnívám, že GOTO lze použít, je to vlastně jediný způsob, jak propadnout.

source: http://msdn.Microsoft.com/en-us/library/aa664749%28v=vs.71%29.aspx

3
Jiří Herník

Zdá se, že do hledání způsobů, jak získat jednu z nejméně používaných syntaxí C #, se zdálo, že je nějaká práce spoustu práce nebo lepší práce. Osobně jsem zjistil, že přepínač prohlášení málokdy stojí za to použít. Důrazně doporučuji analyzovat, jaká data testujete a jaké výsledky chcete.

Řekněme například, že chcete rychle otestovat hodnoty ve známém rozsahu, abyste zjistili, zda se jedná o prvočísla. Chcete se vyhnout tomu, aby váš kód neplýtval výpočty a můžete najít seznam prvočísel v rozsahu, který chcete online. Ke srovnání každé hodnoty se známými prvočísly můžete použít masivní příkaz přepínače.

Nebo můžete jednoduše vytvořit mapu polí připravit a získat okamžité výsledky:

    bool[] Primes = new bool[] {
        false, false, true, true, false, true, false,    
        true, false, false, false, true, false, true,
        false,false,false,true,false,true,false};
    private void button1_Click(object sender, EventArgs e) {
        int Value = Convert.ToInt32(textBox1.Text);
        if ((Value >= 0) && (Value < Primes.Length)) {
            bool IsPrime = Primes[Value];
            textBox2.Text = IsPrime.ToString();
        }
    }

Možná chcete zjistit, zda je znak v řetězci šestnáctkový. Dalo by se použít nevyzpytatelné a poněkud velké prohlášení.

Nebo můžete použít buď regulární výrazy k testování znaku char nebo použít funkci IndexOf k vyhledání znaku v řetězci známých hexadecimálních písmen:

        private void textBox2_TextChanged(object sender, EventArgs e) {
        try {
            textBox1.Text = ("0123456789ABCDEFGabcdefg".IndexOf(textBox2.Text[0]) >= 0).ToString();
        } catch {
        }
    }

Řekněme, že chcete provést jednu ze 3 různých akcí v závislosti na hodnotě, která bude v rozsahu od 1 do 24. Navrhla bych použít sadu prohlášení IF. A pokud se to stalo příliš složitým (nebo čísla byla větší, např. 5 různých akcí v závislosti na hodnotě v rozsahu 1 až 90), pak použijte enum pro definování akcí a vytvoření mapy polí výčtů. Hodnota by pak byla použita k indexování do mapy pole a získání výčtu akce, kterou chcete. Potom použijte buď malou množinu příkazů IF nebo velmi jednoduchý příkaz přepínače pro zpracování výsledné hodnoty enum.

Také Nice věc o mapě pole, která převádí rozsah hodnot do akcí je, že může být snadno změněn kódem. S pevným kabelovým kódem nemůžete snadno měnit chování za běhu, ale s mapou pole je to snadné.

2
Darin

Pokud máte velmi velké množství řetězce (nebo jakéhokoli jiného typu) Případ vše, co dělá totéž, doporučuji použít seznam řetězců v kombinaci s vlastnostmi string.Contains.

Pokud tedy máte velký přepínač:

switch (stringValue)
{
    case "cat":
    case "dog":
    case "string3":
    ...
    case "+1000 more string": //Too many string to write a case for all!
        //Do something;
    case "a lonely case"
        //Do something else;
    .
    .
    .
}

Možná budete chtít nahradit příkaz if takto:

//Define all the similar "case" string in a List
List<string> listString = new List<string>(){ "cat", "dog", "string3", "+1000 more string"};
//Use string.Contains to find what you are looking for
if (listString.Contains(stringValue))
{
    //Do something;
}
else
{
    //Then go back to a switch statement inside the else for the remaining cases if you really need to
}

Toto měřítko dobře pro libovolný počet řetězců případ.

1
Maxter