C # 8开关表达式与多个案例相同的结果

如何编写开关表达式来支持多种情况返回相同的结果?

对于版本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转换为只有一个开关-情况-臂,这样值就不需要重复?

根据“ < em > Rufus L ”的建议更新:

对于我给出的例子,这是有效的。

var switchValue = 3;
var resultText = switchValue switch
{
var x when (x >= 1 && x <= 3) => "one to three",
4 => "four",
5 => "five",
_ => "unknown",
};

但这不是我想要的结果。这仍然只是一种情况(带有过滤条件) ,而不是多种情况产生相同的右侧结果。

58940 次浏览

我想尽办法安装它,但是我还没有找到一种方法来使用新语法为单个 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 语句语法,这似乎是 switch-expression 语法中的一个缺点。正如其他海报所建议的,相当笨拙的 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 语句可读。

我的观点是,如果开关表达式需要共享的结果,并且长度超过几行,那么你最好坚持使用开关表达式。嘘!更冗长,但可能是对你的队友的善意。

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;

如果您的开关类型是标志枚举

[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",
};

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",
};

< a href = “ https://Learn.microsoft.com/en-us/dotnet/cSharp/whats-new/cSharp-9 # pattern-match-enhances”rel = “ noReferrer”> Source


对于旧版本的 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)有更自然的顺序。

如果你仍然在使用 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 =>表示“ else when”,而 _ =>表示“ else”。

我是这样做的:

public string GetValue(string name)
{
return name switch
{
var x when name is "test1" || name is "test2" => "finch",
"test2" => somevalue,
_ => name
};
}