- switch expression — pattern matching expressions using the switch keyword
- Case guards
- Non-exhaustive switch expressions
- C# language specification
- See also
- выражение switch — выражения сопоставления шаблонов с использованием switch ключевое слово
- Охранные условия
- Неисчерпывающие выражения switch
- Спецификация языка C#
- См. также раздел
- Оператор свитч си шарп
- Возвращение значения из switch
- Получение результата из switch
switch expression — pattern matching expressions using the switch keyword
You use the switch expression to evaluate a single expression from a list of candidate expressions based on a pattern match with an input expression. For information about the switch statement that supports switch -like semantics in a statement context, see the switch statement section of the Selection statements article.
The following example demonstrates a switch expression, which converts values of an enum representing visual directions in an online map to the corresponding cardinal directions:
public static class SwitchExample < public enum Direction < Up, Down, Right, Left >public enum Orientation < North, South, East, West >public static Orientation ToOrientation(Direction direction) => direction switch < Direction.Up =>Orientation.North, Direction.Right => Orientation.East, Direction.Down => Orientation.South, Direction.Left => Orientation.West, _ => throw new ArgumentOutOfRangeException(nameof(direction), $"Not expected direction value: "), >; public static void Main() < var direction = Direction.Right; Console.WriteLine($"Map view direction is "); Console.WriteLine($"Cardinal orientation is "); // Output: // Map view direction is Right // Cardinal orientation is East > >
The preceding example shows the basic elements of a switch expression:
- An expression followed by the switch keyword. In the preceding example, it’s the direction method parameter.
- The switch expression arms, separated by commas. Each switch expression arm contains a pattern, an optional case guard, the => token, and an expression.
At the preceding example, a switch expression uses the following patterns:
- A constant pattern: to handle the defined values of the Direction enumeration.
- A discard pattern: to handle any integer value that doesn’t have the corresponding member of the Direction enumeration (for example, (Direction)10 ). That makes the switch expression exhaustive.
For information about the patterns supported by the switch expression and more examples, see Patterns.
The result of a switch expression is the value of the expression of the first switch expression arm whose pattern matches the input expression and whose case guard, if present, evaluates to true . The switch expression arms are evaluated in text order.
The compiler generates an error when a lower switch expression arm can’t be chosen because a higher switch expression arm matches all its values.
Case guards
A pattern may be not expressive enough to specify the condition for the evaluation of an arm’s expression. In such a case, you can use a case guard. A case guard is another condition that must be satisfied together with a matched pattern. A case guard must be a Boolean expression. You specify a case guard after the when keyword that follows a pattern, as the following example shows:
public readonly struct Point < public Point(int x, int y) =>(X, Y) = (x, y); public int X < get; >public int Y < get; >> static Point Transform(Point point) => point switch < < X: 0, Y: 0 >=> new Point(0, 0), < X: var x, Y: var y >when x < y =>new Point(x + y, y), < X: var x, Y: var y >when x > y => new Point(x - y, y), < X: var x, Y: var y >=> new Point(2 * x, 2 * y), >;
The preceding example uses property patterns with nested var patterns.
Non-exhaustive switch expressions
If none of a switch expression’s patterns matches an input value, the runtime throws an exception. In .NET Core 3.0 and later versions, the exception is a System.Runtime.CompilerServices.SwitchExpressionException. In .NET Framework, the exception is an InvalidOperationException. In most cases, the compiler generates a warning if a switch expression doesn’t handle all possible input values. List patterns don’t generate a warning when all possible inputs aren’t handled.
To guarantee that a switch expression handles all possible input values, provide a switch expression arm with a discard pattern.
C# language specification
For more information, see the switch expression section of the feature proposal note.
See also
выражение switch — выражения сопоставления шаблонов с использованием switch ключевое слово
Выражение используется для switch вычисления одного выражения из списка потенциальных выражений на основе совпадения шаблона с входным выражением. Дополнительные сведения об операторе switch , который поддерживает семантику, аналогичную switch , в контексте оператора, см. в разделе об операторе switch статьи Операторы выбора.
В следующем примере демонстрируется выражение switch , которое преобразует значения enum , представляющие визуальные направления на интерактивной карте, в соответствующие стороны света.
public static class SwitchExample < public enum Direction < Up, Down, Right, Left >public enum Orientation < North, South, East, West >public static Orientation ToOrientation(Direction direction) => direction switch < Direction.Up =>Orientation.North, Direction.Right => Orientation.East, Direction.Down => Orientation.South, Direction.Left => Orientation.West, _ => throw new ArgumentOutOfRangeException(nameof(direction), $"Not expected direction value: "), >; public static void Main() < var direction = Direction.Right; Console.WriteLine($"Map view direction is "); Console.WriteLine($"Cardinal orientation is "); // Output: // Map view direction is Right // Cardinal orientation is East > >
В предыдущем примере показаны основные элементы выражения switch .
- Выражение, за которым следует ключевое слово switch . В предыдущем примере это параметр метода direction .
- Ветви выражения switch , разделенные запятыми. Каждая ветвь выражения switch содержит шаблон, необязательное охранное условие, маркер => и выражение.
В предыдущем примере выражение switch использует следующие шаблоны.
- Шаблон константы для обработки определенных значений перечисления Direction .
- Шаблон пустой переменной используется для обработки любых целочисленных значений, которые не имеют соответствующих элементов в перечислении Direction (например, (Direction)10 ). Это делает выражение switch исчерпывающим.
Сведения о шаблонах, поддерживаемых выражением switch и дополнительные примеры см. в статье Шаблоны.
Результатом выражения switch является значение выражения первой ветви switch , чей шаблон соответствует входному выражению, а охранное условие, если таковое есть, принимает значение true . Ветви выражения switch вычисляются в том порядке, в котором они приведены в тексте.
Когда выбрать идущую ниже ветвь выражения switch невозможно, так как идущая выше ветвь switch соответствует всем значениям этого выражения, компилятор выдает ошибку.
Охранные условия
Шаблон может недостаточно полно выражать условие вычисления выражения ветви. В этом случае можно использовать условие ветви. Защита регистра — это еще одно условие, которое должно выполняться вместе с соответствующим шаблоном. Условие случая должно быть логическим выражением. Охранное условие указывается после ключевого слова when , идущего за шаблоном, как показано в следующем примере.
public readonly struct Point < public Point(int x, int y) =>(X, Y) = (x, y); public int X < get; >public int Y < get; >> static Point Transform(Point point) => point switch < < X: 0, Y: 0 >=> new Point(0, 0), < X: var x, Y: var y >when x < y =>new Point(x + y, y), < X: var x, Y: var y >when x > y => new Point(x - y, y), < X: var x, Y: var y >=> new Point(2 * x, 2 * y), >;
В предыдущем примере используются шаблоны свойств с вложенными шаблонами var.
Неисчерпывающие выражения switch
Если ни один из шаблонов выражения switch не соответствует входному значению, среда выполнения выдает исключение. В .NET Core 3.0 и более поздних версиях исключением является System.Runtime.CompilerServices.SwitchExpressionException. В .NET Framework исключением является InvalidOperationException. В большинстве случаев компилятор создает предупреждение, если switch выражение не обрабатывает все возможные входные значения. Шаблоны списков не создают предупреждение, если все возможные входные данные не обрабатываются.
Чтобы гарантировать, что выражение switch обработает все возможные входные значения, укажите ветвь выражения switch с шаблоном пустой переменной.
Спецификация языка C#
Дополнительные сведения см. в разделе о выражении switch в этой заметке о предлагаемых функциях.
См. также раздел
Оператор свитч си шарп
Конструкция switch/case оценивает некоторое выражение и сравнивает его значение с набором значений. И при совпадении значений выполняет определенный код.:
Конструкция switch имеет следующее формальное определение:
После ключевого слова switch в скобках идет сравниваемое выражение. Значение этого выражения последовательно сравнивается со значениями, помещенными после оператора сase . И если совпадение будет найдено, то будет выполняться определенный блок сase .
В конце каждого блока сase должен ставиться один из операторов перехода: break , goto case , return или throw . Как правило, используется оператор break . При его применении другие блоки case выполняться не будут.
string name = «Tom»; switch (name)
В данном случае конструкция switch последовательно сравнивает значение переменной name с набором значений, которые указаны после операторов case . Поскольку здесь значение переменной name — строка «Tom», то будет выполняться блок
case "Tom": Console.WriteLine("Ваше имя - Tom"); break;
Соответственно мы увидим на консоли
Если значение переменной name не совпадает ни с каким значением после операторов case , то ни один из блоков case не выполняется. Однако если даже в этом случае нам все равно надо выполнить какие-нибудь действия, то мы можем добавить в конструкцию switch необязательный блок default . Например:
string name = «Alex»; switch (name)
В данном случае никакое из значений после операторов case не совпадает со значением переменной name, поэтому будет выполняться блок default:
default: Console.WriteLine("Неизвестное имя"); break;
Однако если мы хотим, чтобы, наоборот, после выполнения текущего блока case выполнялся другой блок case, то мы можем использовать вместо break оператор goto case :
int number = 1; switch (number) < case 1: Console.WriteLine("case 1"); goto case 5; // переход к case 5 case 3: Console.WriteLine("case 3"); break; case 5: Console.WriteLine("case 5"); break; default: Console.WriteLine("default"); break; >
Возвращение значения из switch
Конструкция switch позволяет возвращать некоторое значение. Для возвращения значения в блоках case может применятся оператор return . Например, определим следующий метод:
int DoOperation(int op, int a, int b) < switch (op) < case 1: return a + b; case 2: return a - b; case 3: return a * b; default: return 0; >>
В метод DoOperation() передается числовой код операции и два операнда. В зависимости от кода операции над операндами выполнется определенная операция и ее результат возвращается из метода. Для примера при по умолчанию из метода возвращается 0, если код операции не равен 1, 2 или 3.
Затем мы можем вызвать этот метод:
int DoOperation(int op, int a, int b) < switch (op) < case 1: return a + b; case 2: return a - b; case 3: return a * b; default: return 0; >> int result1 = DoOperation(1, 10, 5); // 15 Console.WriteLine(result1); // 15 int result2 = DoOperation(3, 10, 5); // 50 Console.WriteLine(result2); // 50
Получение результата из switch
Хотя конструкция switch в примере выше прекрасно работает, тем не менее мы ее можем сократить и получить результат неосредственно из конструкции switch :
int DoOperation(int op, int a, int b) < int result = op switch < 1 =>a + b, 2 => a - b, 3 => a * b, _ => 0 >; return result; >
Теперь не требуется оператор case , а после сравниваемого значения ставится оператор стрелка => . Значение справа от стрелки выступает в качестве возвращаемоего значения. Кроме того, вместо оператора default используется почерк _. В итоге результат конструкции switch будет присвиваиваться переменной result.
Естестввенно, мы можем сразу возвратить из метода результат без присвоения переменной результата конструкции switch:
int DoOperation(int op, int a, int b) < return op switch < 1 =>a + b, 2 => a - b, 3 => a * b, _ => 0 >; >
Или сделать метод еще короче:
int DoOperation(int op, int a, int b) => op switch < 1 =>a + b, 2 => a - b, 3 => a * b, _ => 0 >;
Обращаю внимание, что данное упрощение касается лишь таких конструкций switch , которые возвращают некоторые значения, как в примере выше.
Стоит отметить, что при возвращении значения из метода, метод должен в любом случае возвращать значение. Например, следующая версия метода не будет работать
int DoOperation(int op, int a, int b) < return op switch < 1 =>a + b, 2 => a - b, 3 => a * b >; >
Эта версия метода возвращает значение, если код операции равен 1, 2 или 3. Но что, если будет передано значение 4 или какое-то другое? Поэтому данная версия метода даже не скомпилируется. Поэтому нам надо предусмотреть возвращение значения из метода при всех возможных вариантах. То есть, мы можем, как в примере выше, добавить в конструкцию switch блок default, в котором будет возвращаться значение при всех остальных случаях.