it-swarm-ru.tech

Несколько случаев в выражении switch

Есть ли способ пролистать несколько операторов без повторного ввода 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;
}

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

524
theo

В C++ и C # нет синтаксиса для второго метода, который вы упомянули.

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

287
Brian R. Bondy

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

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

Этот синтаксис взят из 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

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

68
Neal

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

В C # 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:.
47
Steve Gomez

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

case 1: case 2: case 3:
   break;

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

31
Allan Wind

В .NET Framework 3.5 есть диапазоны:

Enumerable.Range from MSDN

вы можете использовать его с "Содержит" и оператором 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>.

В C # 3.0 нет простого частичное применение для инкапсуляции того факта, что параметр case такой же, но вы создаете небольшой вспомогательный метод (немного многословный, хотя).

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

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

18
Luca Molteni

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

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

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

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

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

Примечание: эквивалентный переключатель в Visual Basic - это выбор.

8
none

Другим вариантом будет использование рутины. Если все случаи 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()
{
   ...
}
7
Dr8k

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

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

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

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

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

Правка: Просто заметил тег C # в вопросе, так что, вероятно, ответ gcc не поможет.

5
DGentry

Одним из менее известных аспектов switch в C # является то, что он опирается на operator =, и, поскольку он может быть переопределен, вы можете получить что-то вроде этого:


string s = foo();

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

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

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

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

допустимо, потому что ни одна секция коммутатора не имеет достижимой конечной точки. В отличие от C и 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

3
Jiří Herník

Кажется, что была проделана огромная работа по поиску способов получить один из наименее используемых синтаксисов C #, чтобы как-то выглядеть лучше или работать лучше. Лично я считаю, что оператор 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.

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

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

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

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

2
Darin

Если у вас очень большое количество строк (или любого другого типа), все делающие одно и то же, я рекомендую использовать строковый список в сочетании со свойством 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
}

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

1
Maxter