C# 8 переключить выражение несколько случаев с одинаковым результатом
Как нужно написать выражение-переключатель для поддержки нескольких случаев, возвращающих один и тот же результат?
С C# до версии 8 переключатель может быть записан так:
var switchValue = 3;
var resultText = string.Empty;
switch (switchValue)
{
case 1:
case 2:
case 3:
resultText = "one to three";
break;
case 4:
resultText = "four";
break;
case 5:
resultText = "five";
break;
default:
resultText = "unkown";
break;
}
Когда я использую синтаксис выражения версии C# 8, это так:
var switchValue = 3;
var resultText = switchValue switch
{
1 => "one to three",
2 => "one to three",
3 => "one to three",
4 => "four",
5 => "five",
_ => "unknown",
};
Итак, мой вопрос: как сделать корпуса 1,2 и 3 только одним переключателем, чтобы значение не нужно было повторять?
Обновление за предложение от "Руфус Л":
Для моего приведенного примера это работает.
var switchValue = 3;
var resultText = switchValue switch
{
var x when (x >= 1 && x <= 3) => "one to three",
4 => "four",
5 => "five",
_ => "unknown",
};
Но это не совсем то, чего я хочу достичь. Это все еще только один случай (с условием фильтра), а не несколько случаев, дающих один и тот же правый результат.
7 ответов
Я нашел время для его установки, но я не нашел способа сделать так, чтобы дело перешло к другому с новым синтаксисом.
Тем не менее, вы можете создать новую переменную, которая захватит значение, а затем использовать условие для представления случаев, которые должны иметь тот же результат:
var resultText = switchValue switch
{
var x when
x == 1 ||
x == 2 ||
x == 3 => "one to three",
4 => "four",
5 => "five",
_ => "unknown",
};
Это на самом деле более кратко, если у вас есть много вариантов для тестирования, потому что вы можете проверить диапазон значений в одной строке:
var resultText = switchValue switch
{
var x when x > 0 && x < 4 => "one to three",
4 => "four",
5 => "five",
_ => "unknown",
};
Пока не появится стандартный синтаксис, я использую следующий метод расширения:
public static bool In<T>(this T val, params T[] vals) => vals.Contains(val);
как это:
var switchValue = 3;
var resultText = switchValue switch
{
var x when x.In(1, 2, 3) => "one, two, or three",
4 => "four",
5 => "five",
_ => "unknown",
};
Это немного короче, чем when x == 1 || x == 2 || x == 3
и имеет более естественный порядок, чем when new [] {1, 2, 3}.Contains(x)
.
К сожалению, это недостаток синтаксиса выражения-переключателя по сравнению с синтаксисом оператора-переключателя. Как предполагали другие плакаты, довольно неуклюжийvar
синтаксис - ваш единственный реальный вариант.
Итак, вы, возможно, надеялись написать:
switchValue switch {
Type1 t1:
Type2 t2:
Type3 t3 => ResultA, // where the ResultX variables are placeholders for expressions.
Type4 t4 => ResultB,
Type5 t5 => ResultC
};
Вместо этого вам нужно будет написать довольно неудобный код ниже с указанием typename:
switchValue switch {
var x when x is Type1 || x is Type2 || x is Type3 => ResultA,
Type4 t4 => ResultB,
Type5 t5 => ResultC
};
В таком простом примере вы, вероятно, сможете жить с этой неловкостью. Но с более сложным примером жить гораздо труднее. Фактически мои примеры на самом деле являются упрощением примера, взятого из нашей собственной кодовой базы, где я надеялся преобразовать оператор-переключатель с примерно шестью результатами, но более чем с десятком вариантов типов, в выражение-переключатель. И результат был явно менее читабельным, чем оператор switch.
Я считаю, что если выражение-переключатель требует общих результатов и имеет длину более нескольких строк, то вам лучше придерживаться оператора-переключателя. Бу! Это более многословно, но, вероятно, из доброты к вашим товарищам по команде.
ResultType tmp;
switch (switchValue) {
case Type1 t1:
case Type2 t2:
case Type3 t3:
tmp = ResultA;
break;
case Type4 t4:
tmp = ResultB;
break;
case Type5 t5:
tmp = ResultC;
break;
};
return tmp;
C#9 решает эту проблему с несколькими случаями:
var result = foo switch
{
1 => ...,
2 or 3 => ...,
_ => throw ...
};
Если вы все еще используете C # 8 и не можете использовать C # 9
1 or 2 or 3 =>
метод, как в ответе выше, вы также можете написать его таким образом, чтобы избежать создания дополнительной переменной с тем же значением, что и
switchValue
как в принятом ответе (который, конечно, совершенно правильный, я просто предлагаю альтернативу, поскольку мне не нравится этот дополнительный
x
).
var list = new List<int> { 3, 4, 5 };
var resultText = switchValue switch
{
1 => "one",
2 => "two",
_ when list.Contains(switchValue) => "three to five",
_ => "unknown",
};
Очевидно, вы можете заменить условие после символа на что угодно, например
switchValue == 3 || switchValue == 4 || switchValue == 5
; суть ответа - показать
_ when
немного.
Я просто думаю о
_ when =>
что означает "иначе, когда" и
_ =>
что означает «еще».
Я сделал таким образом:
public string GetValue(string name)
{
return name switch
{
var x when name is "test1" || name is "test2" => "finch",
"test2" => somevalue,
_ => name
};
}
Если ваш тип переключателя - перечисление флагов
[System.Flags]
public enum Values
{
One = 1,
Two = 2,
Three = 4,
Four = 8,
OneToThree = One | Two | Three
}
var resultText = switchValue switch
{
var x when Values.OneToThree.HasFlag(x) => "one to three",
Values.Four => "4",
_ => "unknown",
};