Несколько случаев в инструкции 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;
}
это синтаксис, о котором я думаю с другого языка, или я что-то упускаю?
14 ответов
нет синтаксиса в C++ или C# для второго метода, который вы упомянули.
нет ничего плохого в вашем первом методе. Если, однако, у вас очень большие диапазоны, просто используйте серию операторов if.
Я думаю, на это уже ответили. Тем не менее, я думаю, что вы все равно можете смешать оба варианта синтаксически лучше, выполнив:
switch (value)
{
case 1: case 2: case 3:
// Do Something
break;
case 4: case 5: case 6:
// Do Something
break;
default:
// Do Something
break;
}
этот синтаксис из Visual Basic выбрать...Оператор Case:
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#. Вместо этого необходимо использовать синтаксис из первого примера.
немного поздно для исходного вопроса, но я публикую этот ответ в надежде, что кто-то использует более новую версию (C# 7 -- доступно по умолчанию в Visual Studio 2017 / .NET Framework 4.6.2), найдет это полезным.
в C# 7 переключение на основе диапазона теперь возможно с помощью переключатель и поможет с 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:
.
вы можете опустить новую строку, которая дает вам:
case 1: case 2: case 3:
break;
но я считаю, что это плохой стиль.
.NET Framework 3.5 имеет диапазоны:
вы можете использовать его с" 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>
.
в C# 3.0 нет просто Частичное Применение чтобы инкапсулировать тот факт, что параметр case одинаковый, но вы создаете небольшой вспомогательный метод (немного подробный, tho).
public static void MySwitchWithEnumerable(int startNumber, int endNumber, Action action){
MySwitchWithEnumerable(3, startNumber, endNumber, action);
}
здесь пример того, как новый функциональный импортированный оператор IMHO более мощный и элегантный, чем старый императивный.
@ Jennifer Owens: вы абсолютно правы код ниже не будет работать:
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-select case.
другой вариант - использовать процедуру. Если все случаи 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()
{
...
}
один менее известный аспект переключатель В C# это то, что он полагается на оператор= и поскольку он может быть переопределен, у вас может быть что-то вроде этого:
string s = foo();
switch (s) {
case "abc": /*...*/ break;
case "def": /*...*/ break;
}
gcc реализует расширение языка C для поддержки последовательных диапазонов:
switch (value)
{
case 1...3:
//Do Something
break;
case 4...6:
//Do Something
break;
default:
//Do the Default
break;
}
редактировать: просто заметил тег C# на вопрос, поэтому, по-видимому, ответ gcc не помогает.
на самом деле мне тоже не нравится команда GOTO, но это в официальных материалах MS, здесь все разрешенные синтаксисы.
если конечная точка списка операторов раздела коммутатора достижима, возникает ошибка времени компиляции. Это правило известно как правило "не проваливаться". Пример
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 можно использовать, это на самом деле единственный способ fallthrough.
источник: http://msdn.microsoft.com/en-us/library/aa664749%28v=vs.71%29.aspx
Кажется, что очень много работы было вложено в поиск способов заставить один из наименее используемых синтаксисов 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.
или вы можете использовать регулярные выражения для проверки char или использовать функция 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 для обработки результирующего значения перечисления.
кроме того, хорошая вещь о карте массива, которая преобразует диапазон значений в действия, заключается в том, что ее можно легко изменить кодом. С жестким проводным кодом вы не можете легко изменить поведение во время выполнения, но с картой массива это легко.
Если у вас очень большое количество строк (или любого другого типа), все делают то же самое, я рекомендую использовать список строк в сочетании со строкой.Содержит свойство.
Итак, если у вас есть большой оператор 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
}
этот масштаб хорошо подходит для любого количества строковых случаев.
для этого вы будете использовать оператор 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's slower
case 4:
goto case 5;
case 5:
goto case 6;
case 6:
goto case 7;
case 7:
DoCase4567();
}