c#8开关表达式多个结果相同的情况

huz*_*zle 8 c# c#-8.0 switch-expression

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

对于版本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;
}
Run Code Online (Sandbox Code Playgroud)

当我使用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",
};
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:如何将案例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",
};
Run Code Online (Sandbox Code Playgroud)

但这并不是我想要完成的。这仍然只是一个案例(具有过滤条件),而不是多个案例产生相同的右手结果。

Zev*_*itz 70

C# 9 支持以下内容:

var switchValue = 3;
var resultText = switchValue switch
{
    1 or 2 or 3 => "one, two, or three",
    4 => "four",
    5 => "five",
    _ => "unknown",
};
Run Code Online (Sandbox Code Playgroud)

或者:

var switchValue = 3;
var resultText = switchValue switch
{
    >= 1 and <= 3 => "one, two, or three",
    4 => "four",
    5 => "five",
    _ => "unknown",
};
Run Code Online (Sandbox Code Playgroud)

来源


对于旧版本的 C#,我使用以下扩展方法:

public static bool In<T>(this T val, params T[] vals) => vals.Contains(val);
Run Code Online (Sandbox Code Playgroud)

像这样:

var switchValue = 3;
var resultText = switchValue switch
{
    var x when x.In(1, 2, 3) => "one, two, or three",
    4 => "four",
    5 => "five",
    _ => "unknown",
};
Run Code Online (Sandbox Code Playgroud)

when x == 1 || x == 2 || x == 3when new [] {1, 2, 3}.Contains(x).

  • 它还分配一个新的临时 Int 数组,如果它在循环内,则会导致 GC 压力,并且比 1 || 慢大约 100 倍。2 - 但这对于大多数代码来说可能并不重要 (4认同)

sfk*_*ach 17

遗憾的是,这似乎是 switch-expression 语法中的一个缺点,相对于 switch-statement 语法。正如其他海报所建议的那样,相当笨拙的var语法是您唯一真正的选择。

所以你可能一直希望你能写:

switchValue switch {
    Type1 t1:
    Type2 t2:
    Type3 t3 => ResultA, // where the ResultX variables are placeholders for expressions.
    Type4 t4 => ResultB,
    Type5 t5 => ResultC
};
Run Code Online (Sandbox Code Playgroud)

相反,您将需要编写下面相当笨拙的代码,并喷上 typename:

switchValue switch {
    var x when x is Type1 || x is Type2 || x is Type 3 => ResultA,
    Type4 t4 => ResultB,
    Type5 t5 => ResultC
};
Run Code Online (Sandbox Code Playgroud)

在这样一个简单的例子中,你可能会忍受这种尴尬。但是更复杂的例子就不太适合了。事实上,我的示例实际上是从我们自己的代码库中提取的一个示例的简化,我希望将一个 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;
Run Code Online (Sandbox Code Playgroud)

  • 我知道这只是一个例子,但是可以通过直接从案例返回而不是设置“tmp”来清理它。这样你也可以省略“break”。 (4认同)
  • @Ben 的评论是公平的,在所有条件相同的情况下,我自己的风格也是如此。但我选择不改变我的回复,因为原来的帖子中实际上没有返回,我希望将计算和返回完全分开,这样重构就更清晰。 (2认同)

Ruf*_*s L 7

我已经开始安装它,但是我还没有找到一种使用新语法将大小写拖入另一个案例的方法。

但是,您可以创建一个新变量来捕获值,然后使用条件表示应该具有相同结果的个案:

var resultText = switchValue switch
{
    var x when
        x == 1 ||
        x == 2 ||
        x == 3 => "one to three",
    4 => "four",
    5 => "five",
    _ => "unknown",
};
Run Code Online (Sandbox Code Playgroud)

如果要测试的情况很多,这实际上会更简洁,因为您可以在一行中测试一系列值:

var resultText = switchValue switch
{
    var x when x > 0 && x < 4 => "one to three",
    4 => "four",
    5 => "five",
    _ => "unknown",
};
Run Code Online (Sandbox Code Playgroud)

  • @PanagiotisKanavos 除了它不是**失败,这就是我的观点。“switch 语句中仅执行一个 switch 部分。C# 不允许从一个 switch 部分继续执行到下一个。因此,以下代码会生成编译器错误 CS0163:“控制无法从一个 case 标签落下(&lt;case label&gt;)到另一个。"" - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch | 这是多个标签的多重匹配。而不是像 Python 中那样用逗号分隔的列表。 (3认同)
  • 跌倒是明确禁止的。无论如何,“when”子句比失败要强大得多。您可以使用单个“var x when listOfValues.Contains(x)”,而不是编写 3 或 10 个“case”语句 (2认同)
  • @PanagiotisKanavos 我刚刚了解到,虽然 Fall Through 是被禁止的,但这并不是 Fall Through。这是允许的多重匹配并编译:https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA+ABATARgLABQGAzAATakDCpA3oaQ+WRjgAykDKAlgF4wAUwAJ4AXGKWABKeozoFGC​​0gGcA7lxFgAFqUHT5ihnIMGwAQyXjWIGccZmLpHNf22 DGAOykAREoC2pgBsArwBuG1cAExgAM1MAVwCRZ1djD29gLgBzUPCFAF9wgpdSQjygA= (2认同)