Ответ 1
Нет синтаксиса в С++ и С# для второго упомянутого вами метода.
Нет ничего плохого в вашем первом методе. Если, однако, у вас очень большие диапазоны, просто используйте ряд утверждений if.
Есть ли способ провалиться через несколько операторов 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;
}
Является ли этот синтаксис, о котором я думаю, с другого языка, или я что-то упускаю?
Нет синтаксиса в С++ и С# для второго упомянутого вами метода.
Нет ничего плохого в вашем первом методе. Если, однако, у вас очень большие диапазоны, просто используйте ряд утверждений 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 Выбрать... Деловая заявка:
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
Вы не можете использовать этот синтаксис в С#. Вместо этого вы должны использовать синтаксис из своего первого примера.
Немного опоздал на исходный вопрос, но я публикую этот ответ в надежде, что кто-то, использующий более новую версию (С# 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:
Вы можете оставить новую строку, которая дает вам:
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>
.
В С# 3.0 нет простого Partial Application, чтобы инкапсулировать тот факт, что параметр case одинаковый, но вы создаете небольшой вспомогательный метод (бит многословный, tho).
public static void MySwitchWithEnumerable(int startNumber, int endNumber, Action action){
MySwitchWithEnumerable(3, startNumber, endNumber, action);
}
Вот пример того, как новый функциональный импортированный оператор IMHO более мощный и элегантный, чем старый императивный.
@Дженнифер Оуэнс: вы абсолютно правы, код ниже не будет работать:
case 1 | 3 | 5:
//not working do something
Единственный способ сделать это:
case 1: case 2: case 3:
// do something
break;
Код, который вы ищете, работает на визуальной основе, где вы легко можете устанавливать диапазоны... ни в коем случае не переключайтесь, а если хотите, блокировки удобнее, я бы предложил в очень экстремальной точке сделать .dll с визуальным базовым и импортируйте обратно в свой проект С#.
Примечание: эквивалент переключателя в визуальном базисе - это случай выбора.
Вот полное решение С# 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;
...
}
Другой вариант - использовать подпрограмму. Если случаи 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()
{
...
}
Еще один известный аспект switch в С# заключается в том, что он полагается на оператор =, и поскольку он может быть переоценен, вы можете иметь что-то вроде этого:
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;
}
Изменить: просто заметил тег С# в вопросе, поэтому, вероятно, ответ gcc не помогает.
На самом деле мне тоже не нравится команда 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
Кажется, что очень много работы было найдено в поиске способов получить один из наименее используемых синтаксисов С#, чтобы как-то выглядеть лучше или работать лучше. Лично я считаю, что оператор 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 для обработки полученного значения перечисления.
Кроме того, хорошая вещь о карте массива, которая преобразует диапазон значений в действия, состоит в том, что ее можно легко изменить с помощью кода. С жестким проводным кодом вы не можете легко изменить поведение во время выполнения, но с картой массива это легко.
Если у вас очень большое количество строк (или любого другого типа), все делающие одно и то же, я рекомендую использовать строковый список в сочетании со свойством 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
}
Этот масштаб хорошо подходит для любого числа строкового регистра.
Чтобы добавить к разговору, используя .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;
}
В С# 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;
}
Для этого вы должны использовать инструкцию 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();
}