如何编写 switch 表达式来支持返回相同结果的多种情况?
对于版本 8 之前的 C#,开关可以这样编写:
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 变成只有一个开关案例臂,这样值就不需要重复?
更新“Rufus L”的建议:
对于我给出的示例,这是可行的。
var switchValue = 3;
var resultText = switchValue switch
{
var x when (x >= 1 && x <= 3) => "one to three",
4 => "four",
5 => "five",
_ => "unknown",
};
但这并不完全是我想要完成的。这仍然只是一种情况(带有过滤条件),而不是多种情况产生相同的右侧结果。
C# 9 支持以下内容:
var switchValue = 3;
var resultText = switchValue switch
{
1 or 2 or 3 => "one, two, or three",
4 => "four",
5 => "five",
_ => "unknown",
};
或者:
var switchValue = 3;
var resultText = switchValue switch
{
>= 1 and <= 3 => "one, two, or three",
4 => "four",
5 => "five",
_ => "unknown",
};
对于旧版本的 C#,我使用以下扩展方法:
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)
更自然。
我开始安装它,但我还没有找到一种方法来使用新语法为单个 switch 部分指定多个单独的 case 标签。
但是,您可以创建一个新变量来捕获该值,然后使用条件来表示应具有相同结果的情况:
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",
};
遗憾的是,相对于 switch 语句语法,这似乎是 C# 8 中 switch 表达式语法的一个缺点。正如其他发帖者所建议的,如果您坚持使用 C# 8,那么相当笨拙的
var
语法是您唯一真正的选择。
所以你可能一直希望你可以写:
switchValue switch {
Type1 t1:
Type2 t2:
Type3 t3 => ResultA, // where the ResultX variables are placeholders for expressions.
Type4 t4 => ResultB,
Type5 t5 => ResultC
};
相反,您需要编写下面相当尴尬的代码,并喷洒类型名:
switchValue switch {
var x when x is Type1 || x is Type2 || x is Type 3 => ResultA,
Type4 t4 => ResultB,
Type5 t5 => ResultC
};
在这样一个简单的例子中,你可能可以忍受这种尴尬。但更复杂的例子则不太容易接受。事实上,我的示例实际上是从我们自己的代码库中提取的示例的简化,我希望将具有大约六个结果但十多个类型情况的 switch 语句转换为 switch 表达式。结果显然比 switch 语句可读性差。
我的观点是,如果 switch 表达式需要共享结果并且长度超过几行,那么最好坚持使用 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 或更高版本,那么您可以使用
or
模式语法。然后你可以写:
return switchValue switch {
Type1 t1 or Type t2 or Type t3 => ResultA,
Type4 t4 => ResultB,
Type5 t5 => ResultC
_ => default
};
如果您仍在使用 C# 8,因此无法使用上述答案中的 C# 9
1 or 2 or 3 =>
方法,您还可以以一种避免创建与以下值相同的额外变量 x
的方式编写它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",
};
显然,您可以将
_ when
之后的条件替换为任何内容,例如 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",
};
or
运算符:
var switchValue = 3;
var resultText = switchValue switch
{
1 or
2 or
3 => "one to three",
4 => "four",
5 => "five",
_ => "unknown",
};