Несколько случаев в инструкции switch

Есть ли способ провалиться через несколько операторов case, не повторяя case value: повторно?

Я знаю, что это работает:

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

но я хотел бы сделать что-то вроде этого:

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

Является ли этот синтаксис, о котором я думаю, с другого языка, или я что-то упускаю?

Ответ 1

Нет синтаксиса в С++ и С# для второго упомянутого вами метода.

Нет ничего плохого в вашем первом методе. Если, однако, у вас очень большие диапазоны, просто используйте ряд утверждений if.

Ответ 2

Думаю, об этом уже ответили. Тем не менее, я думаю, что вы все равно можете сочетать оба варианта синтаксически лучшим способом:

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

Ответ 3

Этот синтаксис относится к Visual Basic Выбрать... Деловая заявка:

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

Вы не можете использовать этот синтаксис в С#. Вместо этого вы должны использовать синтаксис из своего первого примера.

Ответ 4

Немного опоздал на исходный вопрос, но я публикую этот ответ в надежде, что кто-то, использующий более новую версию (С# 7 - доступная по умолчанию в Visual Studio 2017/.NET Framework 4.6.2), найдет ее полезной.

В С# 7 переключение на основе диапазона теперь возможно с помощью оператора switch и может помочь с проблемой OP.

Пример:

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

Заметки:

  • Скобки ( и ) не обязательны в условии when, но используются в этом примере, чтобы выделить сравнение (я).
  • var также может использоваться вместо int. Например: case var n when n >= 7:

Ответ 5

Вы можете оставить новую строку, которая дает вам:

case 1: case 2: case 3:
   break;

но я считаю этот плохой стиль.

Ответ 6

.NET Framework 3.5 имеет диапазоны:

Enumerable.Range из MSDN

вы можете использовать его с "contains" и оператором IF, так как, как сказал кто-то, оператор SWITCH использует оператор "==".

Вот пример:

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

Но я думаю, что мы можем получать больше удовольствия: поскольку вам не нужны значения возврата, и это действие не принимает параметров, вы можете легко использовать действия!

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

Старый пример с помощью этого нового метода:

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

Поскольку вы передаете действия, а не значения, вы должны опустить скобки, это очень важно. Если вам нужна функция с аргументами, просто измените тип Action на Action<ParameterType>. Если вам нужны значения возврата, используйте Func<ParameterType, ReturnType>.

В С# 3.0 нет простого Partial Application, чтобы инкапсулировать тот факт, что параметр case одинаковый, но вы создаете небольшой вспомогательный метод (бит многословный, tho).

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

Вот пример того, как новый функциональный импортированный оператор IMHO более мощный и элегантный, чем старый императивный.

Ответ 7

@Дженнифер Оуэнс: вы абсолютно правы, код ниже не будет работать:

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

Единственный способ сделать это:

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

Код, который вы ищете, работает на визуальной основе, где вы легко можете устанавливать диапазоны... ни в коем случае не переключайтесь, а если хотите, блокировки удобнее, я бы предложил в очень экстремальной точке сделать .dll с визуальным базовым и импортируйте обратно в свой проект С#.

Примечание: эквивалент переключателя в визуальном базисе - это случай выбора.

Ответ 8

Вот полное решение С# 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;
}

Работает со строками тоже...

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

Ответ 9

Другой вариант - использовать подпрограмму. Если случаи 1-3 выполняют одну и ту же логику, тогда оберните эту логику в подпрограмму и вызовите ее для каждого случая. Я знаю, что это на самом деле не избавляет от аргументов case, но оно реализует хороший стиль и сохраняет обслуживание до минимума.....

[Edit] Добавлена ​​альтернативная реализация для соответствия оригинальному вопросу... [/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()
{
   ...
}

Ответ 10

Еще один известный аспект switch в С# заключается в том, что он полагается на оператор =, и поскольку он может быть переоценен, вы можете иметь что-то вроде этого:


string s = foo();

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

Ответ 11

gcc реализует расширение для языка C для поддержки последовательных диапазонов:

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

Изменить: просто заметил тег С# в вопросе, поэтому, вероятно, ответ gcc не помогает.

Ответ 12

На самом деле мне тоже не нравится команда GOTO, но в официальных материалах MS здесь все разрешены синтаксисы.

Если конечная точка списка операторов секции переключения достижима, возникает ошибка времени компиляции. Это известно как правило "без падения". Пример

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

действителен, потому что никакой раздел переключения не имеет конечной точки достижимости. В отличие от C и С++ выполнение секции переключения не разрешается "проваливаться" в следующий раздел коммутатора, а пример

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

приводит к ошибке времени компиляции. Когда выполнение секции коммутатора должно сопровождаться выполнением другого раздела коммутатора, следует использовать явный код goto или goto по умолчанию:

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

Несколько разрешений разрешены в разделе коммутатора. Пример

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

Я верю в этот конкретный случай, GOTO можно использовать, это на самом деле единственный способ провалиться.

источник: http://msdn.microsoft.com/en-us/library/aa664749%28v=vs.71%29.aspx

Ответ 13

Кажется, что очень много работы было найдено в поиске способов получить один из наименее используемых синтаксисов С#, чтобы как-то выглядеть лучше или работать лучше. Лично я считаю, что оператор switch редко стоит использовать. Я бы настоятельно предложил проанализировать, какие данные вы тестируете, и конечные результаты, которые вы хотите.

Скажем, например, вы хотите быстро проверить значения в известном диапазоне, чтобы увидеть, являются ли они простыми числами. Вы хотите, чтобы ваш код не делал расточительных вычислений, и вы можете найти список простых чисел в диапазоне, который вы хотите в Интернете. Вы можете использовать массивный оператор switch для сравнения каждого значения с известными простыми числами.

Или вы можете просто создать карту массивов простых чисел и получить немедленные результаты:

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

Возможно, вы хотите увидеть, является ли символ в строке шестнадцатеричным. Вы можете использовать неопределенный и несколько большой оператор switch.

Или вы можете использовать либо регулярные выражения для тестирования char, либо использовать функцию IndexOf для поиска char в строке известных шестнадцатеричных букв:

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

Предположим, вы хотите сделать одно из трех разных действий в зависимости от значения, которое будет в диапазоне от 1 до 24. Я бы предложил использовать набор операторов IF. И если это стало слишком сложным (или числа были больше, например, 5 различных действий в зависимости от значения в диапазоне от 1 до 90), то используйте перечисление для определения действий и создания карты массивов перечислений. Затем значение будет использовано для индексации в карте массива и получения перечисления необходимого действия. Затем используйте либо небольшой набор операторов IF, либо очень простой оператор switch для обработки полученного значения перечисления.

Кроме того, хорошая вещь о карте массива, которая преобразует диапазон значений в действия, состоит в том, что ее можно легко изменить с помощью кода. С жестким проводным кодом вы не можете легко изменить поведение во время выполнения, но с картой массива это легко.

Ответ 14

Если у вас очень большое количество строк (или любого другого типа), все делающие одно и то же, я рекомендую использовать строковый список в сочетании со свойством string.Contains.

Так что если у вас есть большой оператор switch, например:

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

Возможно, вы захотите заменить его оператором if следующим образом:

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

Этот масштаб хорошо подходит для любого числа строкового регистра.

Ответ 15

Чтобы добавить к разговору, используя .NET 4.6.2, я также смог сделать следующее. Я проверил код, и он работал на меня.

Вы также можете сделать несколько операторов "ИЛИ", как показано ниже:

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

Вы также можете проверить, соответствует ли оно значению в массиве:

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

Ответ 16

В С# 7 у нас теперь есть Pattern Matching, так что вы можете сделать что-то вроде:

switch (age)
{
  case 50:
    ageBlock = "the big five-oh";
    break;
  case var testAge when (new List<int>()
      { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89 }).Contains(testAge):
    ageBlock = "octogenarian";
    break;
  case var testAge when ((testAge >= 90) & (testAge <= 99)):
    ageBlock = "nonagenarian";
    break;
  case var testAge when (testAge >= 100):
    ageBlock = "centenarian";
    break;
  default:
    ageBlock = "just old";
    break;
}

Ответ 17

Для этого вы должны использовать инструкцию goto. Например:

    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 slower
    case 4:
        goto case 5;
    case 5:
        goto case 6;
    case 6:
        goto case 7;
    case 7:
        DoCase4567();
    }