it-swarm-eu.dev

Mehrere Fälle in switch-Anweisung

Gibt es eine Möglichkeit, mehrere case-Anweisungen durchzugehen, ohne wiederholt case value: anzugeben?

Ich weiß, dass dies funktioniert:

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

aber ich würde gerne so etwas machen:

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

Entspricht diese Syntax einer anderen Sprache oder fehlt mir etwas?

536
theo

Für die zweite von Ihnen erwähnte Methode gibt es weder in C++ noch in C # eine Syntax.

An Ihrer ersten Methode ist nichts auszusetzen. Wenn Sie jedoch sehr große Bereiche haben, verwenden Sie einfach eine Reihe von if-Anweisungen.

293
Brian R. Bondy

Ich denke, das wurde bereits beantwortet. Ich denke jedoch, dass Sie beide Optionen syntaktisch noch besser mischen können, indem Sie Folgendes tun:

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

Diese Syntax stammt aus Visual Basic Select ... 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

Sie können diese Syntax in C # nicht verwenden. Stattdessen müssen Sie die Syntax aus Ihrem ersten Beispiel verwenden.

70
Neal

Ein bisschen zu spät für die ursprüngliche Frage, aber ich poste diese Antwort in der Hoffnung, dass jemand mit einer neueren Version ( C # 7 - standardmäßig in Visual Studio 2017/.NET Framework 4.6 verfügbar .2 ), wird es hilfreich finden.

In C # 7 ist das bereichsbezogene Schalten jetzt mit der Anweisung switch möglich und würde bei dem Problem des OP helfen.

Beispiel:

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

Anmerkungen:

  • Die Klammern ( und ) sind in der Bedingung when nicht erforderlich, werden jedoch in diesem Beispiel verwendet, um die Vergleiche hervorzuheben.
  • var kann auch anstelle von int verwendet werden. Zum Beispiel: case var n when n >= 7:.
51
Steve Gomez

Sie können die Zeilenumbrüche weglassen, die Folgendes enthalten:

case 1: case 2: case 3:
   break;

aber ich betrachte diesen schlechten Stil.

31
Allan Wind

.NET Framework 3.5 verfügt über Bereiche:

Enumerable.Range from MSDN

sie können es mit "contain" und der IF-Anweisung verwenden, da die SWITCH-Anweisung, wie jemand sagte, den Operator "==" verwendet.

Hier ein Beispiel:

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

Aber ich denke, wir können mehr Spaß haben: Da Sie die Rückgabewerte nicht benötigen und diese Aktion keine Parameter benötigt, können Sie einfach Aktionen verwenden!

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

Das alte Beispiel mit dieser neuen Methode:

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

Da Sie keine Werte, sondern Aktionen übergeben, sollten Sie die Klammern weglassen. Dies ist sehr wichtig. Wenn Sie eine Funktion mit Argumenten benötigen, ändern Sie einfach den Typ von Action in Action<ParameterType>. Wenn Sie Rückgabewerte benötigen, verwenden Sie Func<ParameterType, ReturnType>.

In C # 3.0 gibt es kein einfaches Partial Application , um die Tatsache zu kapseln, dass der case-Parameter derselbe ist, aber Sie erstellen eine kleine Hilfsmethode (ein bisschen ausführlich, tho).

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

Hier ein Beispiel, wie neue funktionale importierte Anweisungen IMHO mächtiger und eleganter sind als die alten imperativen.

18
Luca Molteni

@ Jennifer Owens: Sie haben absolut Recht, der folgende Code wird nicht funktionieren:

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

Der einzige Weg dies zu tun ist:

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

Der Code, nach dem Sie suchen, funktioniert in Visual Basic, wo Sie problemlos Bereiche einfügen können ... in keiner Option des Schalters zu Ihrem C # -Projekt.

Hinweis: Schalteräquivalent in Visual Basic ist Groß-/Kleinschreibung.

8
none

Eine andere Option wäre die Verwendung einer Routine. Wenn die Fälle 1 bis 3 alle dieselbe Logik ausführen, schließen Sie diese Logik in eine Routine ein und rufen Sie sie für jeden Fall auf. Ich weiß, dass dies die case-Anweisungen nicht wirklich loswird, aber es implementiert einen guten Stil und reduziert die Wartung auf ein Minimum .....

[Bearbeiten] Alternative Implementierung hinzugefügt, um der ursprünglichen Frage zu entsprechen ... [/ Bearbeiten]

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

Hier ist die vollständige C # 7-Lösung ...

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

Funktioniert auch mit Streichern ...

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

gcc implementiert eine Erweiterung der C-Sprache, um sequentielle Bereiche zu unterstützen:

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

Bearbeiten: Ich habe gerade das C # -Tag auf der Frage bemerkt, daher hilft vermutlich eine gcc-Antwort nicht weiter.

5
DGentry

Eine weniger bekannte Facette von switch in C # ist, dass es sich auf operator = stützt, und da es überschrieben werden kann, könnten Sie so etwas haben:


string s = foo();

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

Eigentlich mag ich den GOTO-Befehl auch nicht, aber er ist in offiziellen MS-Materialien enthalten. Hier sind alle zulässigen Syntaxen.

Wenn der Endpunkt der Anweisungsliste eines Switch-Abschnitts erreichbar ist, tritt ein Fehler beim Kompilieren auf. Dies wird als "No Fall Through" -Regel bezeichnet. Das Beispiel

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

ist gültig, weil kein Schaltabschnitt einen erreichbaren Endpunkt hat. Im Gegensatz zu C und C++ darf die Ausführung eines Switch-Abschnitts nicht auf den nächsten Switch-Abschnitt und das Beispiel "durchfallen"

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

führt zu einem Fehler bei der Kompilierung. Wenn auf die Ausführung eines Switch-Abschnitts die Ausführung eines anderen Switch-Abschnitts folgen soll, muss eine explizite goto-case- oder goto-default-Anweisung verwendet werden:

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

In einem Schaltabschnitt sind mehrere Bezeichnungen zulässig. Das Beispiel

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

Ich glaube in diesem speziellen Fall kann das GOTO verwendet werden, es ist eigentlich der einzige Weg, durchzukommen.

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

3
Jiří Herník

Es scheint sehr viel Arbeit darauf verwendet worden zu sein, eine der am wenigsten verwendeten C # -Syntaxen so zu gestalten, dass sie irgendwie besser aussieht oder besser funktioniert. Persönlich finde ich, dass die switch-Anweisung selten sinnvoll ist. Ich würde dringend empfehlen, zu analysieren, welche Daten Sie testen und welche Endergebnisse Sie wünschen.

Angenommen, Sie möchten schnell Werte in einem bekannten Bereich testen, um festzustellen, ob es sich um Primzahlen handelt. Sie möchten vermeiden, dass Ihr Code die verschwenderischen Berechnungen durchführt, und Sie können eine Liste von Primzahlen im gewünschten Bereich online finden. Sie können eine massive switch-Anweisung verwenden, um jeden Wert mit bekannten Primzahlen zu vergleichen.

Oder Sie können einfach eine Array-Karte mit Primzahlen erstellen und sofortige Ergebnisse erzielen:

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

Vielleicht möchten Sie sehen, ob ein Zeichen in einer Zeichenfolge hexadezimal ist. Sie könnten eine unfreundliche und etwas große switch-Anweisung verwenden.

Sie können auch reguläre Ausdrücke verwenden, um das Zeichen zu testen, oder die IndexOf-Funktion verwenden, um in einer Zeichenfolge bekannter Hexadezimalbuchstaben nach dem Zeichen zu suchen:

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

Angenommen, Sie möchten eine von drei verschiedenen Aktionen ausführen, abhängig von einem Wert im Bereich von 1 bis 24. Ich würde vorschlagen, eine Reihe von IF-Anweisungen zu verwenden. Und wenn dies zu komplex wurde (oder die Zahlen größer waren, wie z. B. 5 verschiedene Aktionen, abhängig von einem Wert im Bereich von 1 bis 90), definieren Sie die Aktionen mithilfe einer Aufzählung und erstellen Sie eine Array-Zuordnung der Aufzählungen. Der Wert wird dann verwendet, um die Array-Zuordnung zu indizieren und die Aufzählung der gewünschten Aktion abzurufen. Verwenden Sie dann entweder eine kleine Menge von IF-Anweisungen oder eine sehr einfache switch-Anweisung, um den resultierenden Enum-Wert zu verarbeiten.

Das Schöne an einer Array-Map, die einen Bereich von Werten in Aktionen umwandelt, ist auch, dass sie einfach per Code geändert werden kann. Mit fest verdrahtetem Code kann man das Verhalten zur Laufzeit nicht leicht ändern, aber mit einer Array-Map ist es einfach.

2
Darin

Wenn Sie eine sehr große Menge an Zeichenfolgen (oder einen anderen Typ) haben, empfiehlt sich die Verwendung einer Zeichenfolgenliste in Kombination mit der Eigenschaft string.Contains.

Also, wenn Sie eine große switch-Anweisung wie folgt haben:

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

Möglicherweise möchten Sie es durch eine if-Anweisung wie die folgende ersetzen:

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

Diese Skala eignet sich für eine beliebige Anzahl von Saiten.

1
Maxter

Um die Konversation zu erweitern, konnte ich mit .NET 4.6.2 auch Folgendes tun. Ich habe den Code getestet und es hat bei mir funktioniert.

Sie können auch mehrere "OR" -Anweisungen wie folgt ausführen:

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

Sie können auch überprüfen, ob es mit einem Wert in einem Array übereinstimmt:

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