Meerdere hoofdletters in switch-statement

Is er een manier om door meerdere case-statements te bladeren zonder herhaaldelijk case value:te vermelden?

Ik weet dat dit werkt:

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;
}

maar ik zou zoiets als dit willen doen:

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

Is deze syntaxis waar ik aan denk uit een andere taal, of mis ik iets?


Antwoord 1, autoriteit 100%

Er is geen syntaxis in C++ of C# voor de tweede methode die u noemde.

Er is niets mis met je eerste methode. Als je echter zeer grote bereiken hebt, gebruik dan gewoon een reeks if-statements.


Antwoord 2, autoriteit 95%

Volgens mij is dit al beantwoord. Ik denk echter dat je beide opties nog steeds syntactisch beter kunt combineren door:

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

Antwoord 3, autoriteit 26%

In C # 7 (standaard beschikbaar in Visual Studio 2017 / .NET Framework 4.6.2), bereikgerichte schakeling is nu mogelijk met de Schakel statement en zou helpen met het probleem van de OP.

Voorbeeld:

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

Opmerkingen:

  • De haakjes (en )zijn niet vereist in de whenConditie, maar in dit voorbeeld worden gebruikt om de vergelijking (en) te markeren .
  • varkan ook worden gebruikt in plaats van int. Bijvoorbeeld: case var n when n >= 7:.

4, Autoriteit 21%

Deze syntaxis is van de visuele basis Selecteer … Case-statement :

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

U kunt deze syntaxis niet gebruiken in C#. In plaats daarvan moet je de syntaxis van je eerste voorbeeld gebruiken.


Antwoord 5, autoriteit 10%

Je kunt de nieuwe regel weglaten die je het volgende geeft:

case 1: case 2: case 3:
   break;

maar dat vind ik een slechte stijl.


Antwoord 6, autoriteit 6%

.NET Framework 3.5 heeft bereiken:

Enumerable.Range van MSDN

je kunt het gebruiken met “bevat” en de IF-instructie, aangezien zoals iemand zei, de SWITCH-instructie de “==” operator gebruikt.

Hier een voorbeeld:

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

Maar ik denk dat we meer plezier kunnen hebben: aangezien je de retourwaarden niet nodig hebt en deze actie geen parameters vereist, kun je gemakkelijk acties gebruiken!

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

Het oude voorbeeld met deze nieuwe methode:

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

Omdat je acties en geen waarden doorgeeft, moet je de haakjes weglaten, dit is erg belangrijk. Als je een functie met argumenten nodig hebt, verander dan gewoon het type Actionin Action<ParameterType>. Als u retourwaarden nodig heeft, gebruikt u Func<ParameterType, ReturnType>.

In C# 3.0 is er geen gemakkelijke Gedeeltelijke toepassingom het feit dat de parameter case is hetzelfde, maar je maakt een kleine hulpmethode (een beetje uitgebreid, dat wel).

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

Hier een voorbeeld van hoe een nieuwe functionele geïmporteerde verklaring IMHO krachtiger en eleganter is dan de oude imperatief.


Antwoord 7, autoriteit 5%

Hier is de complete C# 7-oplossing…

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;
}

Het werkt ook met strings…

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

Antwoord 8, autoriteit 4%

De onderstaande code werkt niet:

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

De enige manier om dit te doen is:

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

De code die u zoekt werkt in Visual Basic, waar u gemakkelijk bereiken kunt plaatsen… in de optie nonevan de switch-instructie of if elseblokkeert handig, raad ik aan om op een zeer extreem punt .dll te maken met Visual Basic en terug te importeren naar uw C#-project.

Opmerking: het switch-equivalent in Visual Basic is Select Case.


Antwoord 9, autoriteit 2%

Met C#9 kwam de Relational Pattern Matching. Dit stelt ons in staat om het volgende te doen:

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

In diepgaande tutorial van Relational Patter in C# 9

Patroonovereenkomstige wijzigingen voor C# 9.0

Relationele patronen stellen de programmeur in staat om die input uit te drukken
waarde moet voldoen aan een relationele beperking in vergelijking met een constante
waarde


Antwoord 10, autoriteit 2%

Een andere optie zou zijn om een routine te gebruiken. Als gevallen 1-3 allemaal dezelfde logica uitvoeren, wikkel die logica dan in een routine en roep het voor elk geval aan. Ik weet dat dit niet echt van de case-statements afkomt, maar het implementeert wel een goede stijl en beperkt het onderhoud tot een minimum…..

[Bewerken] Alternatieve implementatie toegevoegd die overeenkomt met de oorspronkelijke vraag…[/Bewerken]

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()
{
   ...
}

11

Een minder bekende facet van Switch in C # is dat het op de -operator = vertrouwt en omdat het kan worden ingrijpt, zou u zoiets kunnen hebben:


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

12

GCC implementeert een uitbreiding van de C-taal om opeenvolgende reeksen te ondersteunen:

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

Bewerken : Net opmerkte de C # -tag op de vraag, dus vermoedelijk helpt een GCC-antwoord niet.


13

Eigenlijk vind ik het Goto-commando ook niet leuk, maar het is in officiële Microsoft-materialen, en hier zijn allemaal toegestane syntaxis.

Als het eindpunt van de instructielijst van een switch-sectie bereikbaar is, treedt er een compileer-tijdfout op. Dit staat bekend als de “No Fall Through” -regel. Het voorbeeld

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

is geldig omdat er geen sectie-sectie een bereikbaar eindpunt heeft. In tegenstelling tot C en C++ is de uitvoering van een switch-sectie niet toegestaan ​​om “door te vallen” naar de sectie Volgende schakelaar, en het voorbeeld

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

resulteert in een compilertijdfout. Wanneer de uitvoering van een switch-sectie moet worden gevolgd door uitvoering van een ander schakelaargedeelte, moet een expliciete GOTO- of GOTO-standaardverklaring worden gebruikt:

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

Meerdere labels zijn toegestaan ​​in een schakelgedeelte. Het voorbeeld

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

Ik geloof dat in dit specifieke geval de GOTO kan worden gebruikt, en het is eigenlijk de enige manier om er doorheen te komen.

Bron


Antwoord 14

In C# 8.0 kun je de nieuwe van expressie wisselensyntaxis die ideaal is voor uw geval.

var someOutput = value switch
{
    >= 1 and <= 3 => <Do some stuff>,
    >= 4 and <= 6 => <Do some different stuff>,
    _ => <Default stuff>
};

Antwoord 15

Er lijkt ontzettend veel werk te zijn gestoken in het vinden van manieren om een van de minst gebruikte syntaxis van C# er op de een of andere manier beter uit te laten zien of beter te laten werken. Persoonlijk vind ik de switch-statement zelden de moeite waard om te gebruiken. Ik raad je ten zeerste aan om te analyseren welke gegevens je aan het testen bent en welke eindresultaten je wilt.

Stel bijvoorbeeld dat u snel waarden in een bekend bereik wilt testen om te zien of het priemgetallen zijn. U wilt voorkomen dat uw code de verspillende berekeningen doet en u kunt online een lijst met priemgetallen vinden in het bereik dat u wilt. Je zou een massieve switch-instructie kunnen gebruiken om elke waarde te vergelijken met bekende priemgetallen.

Of u kunt gewoon een matrixkaart van priemgetallen maken en onmiddellijk resultaat krijgen:

   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();
        }
    }

Misschien wil je zien of een teken in een string hexadecimaal is. Je zou een lelijke en ietwat grote switch-statement kunnen gebruiken.

Of je kunt ofwel reguliere expressies gebruiken om de char te testen of de IndexOf-functie gebruiken om naar de char te zoeken in een reeks bekende hexadecimale letters:

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

Stel dat je een van de 3 verschillende acties wilt uitvoeren, afhankelijk van een waarde die in het bereik van 1 tot 24 ligt. Ik raad je aan een set IF-instructies te gebruiken. En als dat te complex werd (of de getallen waren groter, zoals 5 verschillende acties, afhankelijk van een waarde in het bereik van 1 tot 90), gebruik dan een opsomming om de acties te definiëren en een matrixkaart van de opsommingen te maken. De waarde zou dan worden gebruikt om te indexeren in de matrixkaart en de opsomming te krijgen van de gewenste actie. Gebruik dan ofwel een kleine set IF-statements of een heel eenvoudig switch-statement om de resulterende opsommingswaarde te verwerken.

Het leuke van een matrixkaart die een reeks waarden in acties omzet, is dat deze eenvoudig door code kan worden gewijzigd. Met vast bedrade code kun je het gedrag tijdens runtime niet gemakkelijk veranderen, maar met een array-kaart is het gemakkelijk.


Antwoord 16

Als je een heel groot aantal strings (of een ander type) hebt die allemaal hetzelfde doen, raad ik het gebruik van een stringlijst aan in combinatie met de eigenschap string.Contains.

Dus als je een grote switch-statement hebt, zoals:

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;
    .
    .
    .
}

Misschien wilt u het vervangen door een if-statement zoals dit:

// 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
}

Deze schaal goed voor een willekeurig aantal tekenreeksen.


Antwoord 17

Ik denk dat deze beter is in C# 7 of hoger.

switch (value)
{
    case var s when new[] { 1,2 }.Contains(s):
    // Do something
     break;
    default:
    // Do the default
    break;
 }

Je kunt het bereik ook controleren in de C#-switch: Switch case: kan ik een bereik gebruiken in plaats van een één nummer
Of als u de basis van
C#-switchcase


Antwoord 18

Om toe te voegen aan het gesprek, met .NET 4.6.2 kon ik ook het volgende doen.
Ik heb de code getest en het werkte voor mij.

U kunt ook meerdere “OF”-instructies doen, zoals hieronder:

           switch (value)
            {
                case string a when a.Contains("text1"):
                    // Do Something
                    break;
                case string b when b.Contains("text3") || b.Contains("text4") || b.Contains("text5"):
                    // Do Something else
                    break;
                default:
                    // Or do this by default
                    break;
            }

Je kunt ook controleren of het overeenkomt met een waarde in een array:

           string[] statuses = { "text3", "text4", "text5"};
            switch (value)
            {
                case string a when a.Contains("text1"):
                    // Do Something
                    break;
                case string b when statuses.Contains(value):                        
                    // Do Something else
                    break;
                default:
                    // Or do this by default
                    break;
            }

Antwoord 19

U kunt ook voorwaarden hebben die totaal anders zijn

           bool isTrue = true;
            switch (isTrue)
            {
                case bool ifTrue when (ex.Message.Contains("not found")):
                case bool ifTrue when (thing.number = 123):
                case bool ifTrue when (thing.othernumber != 456):
                    response.respCode = 5010;
                    break;
                case bool ifTrue when (otherthing.text = "something else"):
                    response.respCode = 5020;
                    break;
                default:
                    response.respCode = 5000;
                    break;
            }

Antwoord 20

Hiervoor zou je een goto-statement gebruiken. Zoals:

   switch(value){
    case 1:
        goto case 3;
    case 2:
        goto case 3;
    case 3:
        DoCase123();
    //This would work too, but I'm not sure if it's slower
    case 4:
        goto case 5;
    case 5:
        goto case 6;
    case 6:
        goto case 7;
    case 7:
        DoCase4567();
    }

Other episodes