void 方法的 C# 8 switch 表达式

C# 8 switch expression for void methods

我知道 C# 8 switch expression 语法用于 return 一个值或 属性 匹配的方法。但是,如果我们只需要打开一个字符串值并执行一个 return 什么都没有的方法(没有 return type/void),那么我们如何去做呢?我在想某种形式的 Func 但不确定确切的语法。我知道我们可以用常规的 case 语句以旧的方式做到这一点,但我想看看我们是否可以用更新的语法实现同样的效果。

这是问题的例子

switch (stringvalue)
{
    case "Add": Add(); break;
    case "Subtract": Subtract(); break;
}

可能是这样的:

stringvalue switch
{
    "Add" => Add(),
    "Subtract" => Subtract()
}
// but this complains that there needs to be assignment on left side for this

这可能吗?

TL;DR

不可能C# 8switch expression不能returnvoid.它必须 return 一个值并且必须使用该值(分配给变量,作为参数传递给方法,return 作为方法的结果等)。但是有一个解决方法。我们可以写一个 switch expression,return 是一个 delegate(例如 Action 类型),然后立即调用它:

(stringValue switch
 {
    "Add" => (Action) Add,
    "Subtract" => Subtract,
    _ => throw new ArgumentOutOfRangeException()
 })();

这种方法也可以与 expression bodied methods 一起使用。这里是 demo.


说明

Is this possible?

C# 8中是不可能的。 C# specification.

中描述了此限制

参考C# specification。从第 Recursive Pattern Matching - Switch Expression and Statements 页我们可以了解到:

  • The switch_expression is not permitted as an expression_statement.

  • An expression_statement evaluates a given expression. The value computed by the expression, if any, is discarded.

从这两条语句可以得出,switch_expression不能用在expression_statement的上下文中,其结果值不能 ]被丢弃。必须使用结果值,例如,必须将其分配给变量、作为参数传递给方法或作为方法的结果 returned。因此编译器抱怨说 switch expression 不能用作语句。


if we just need to switch on a string value and execute a method that returns nothing (no return type/void), how do we go about it? I am thinking some form of Func but not sure of the exact syntax.

我们可以使用下一个方法:写一个switch expression,return是一个delegate,然后立即调用它。例如:

(stringValue switch
 {
    "Add" => (Action) Add,
    "Subtract" => Subtract,
    _ => throw new ArgumentOutOfRangeException()
 })();

这个方法也可以用来声明expression bodied members:

private static void Demo(string str) =>
    (str switch
     {
         "Add" => (Action) Add,
         "Subtract" => Subtract,
         _ => throw new ArgumentOutOfRangeException()
     })();

这里是complete sample.

在我看来,这样的变通方法看起来很难看,我个人更愿意使用 switch-caseif-else 而不是这样的构造。

感谢 l33t 的评论。 他指出,使用这种方法会导致每个 case expression 遭受非常昂贵的 delegate allocation(在 .NET 5).所以这是不使用这种方法而更喜欢使用 switch-caseif-else.

的另一个原因

可能在以后的版本C#中会放宽这个限制(see this link):

The switch_expression is not permitted as an expression_statement.

We are looking at relaxing this in a future revision.

但是我在csharplang repo中没有找到合适的方案。

正如 Iliar 告诉你的那样,这是不可能的。我有时使用的解决方法是添加一个始终 returns true 的本地函数,并且我在 switch 分配中使用了一个丢弃字符。我发现此解决方法比使用委托的方法更清晰。

例如,您可以在切换之前将此添加到您的代码中:

bool Add() { [HEREYOURCODEToAdd]; return true;}
bool Substract() { [HEREYOURCODETOSubstract]; return true;}

然后你会这样称呼它:

_ = stringvalue switch {
    "Add" => Add(),
    "Substract" => Substract(),
};

我认为这种方法有一些用例。例如,如果你想在开关中使用元组模式,它会比许多废弃的 if 更具可读性。这是我正在使用的代码,我认为这种方法比 ifs:

           bool agregar(int índiceInicial, int índiceFinal) { visitasJson.Add(json[índiceInicial..índiceFinal]); return true; };
            _ = (índiceInicial, índiceFinal) switch {
                (0, -1) => agregar(índiceInicial + 1, índiceFinal - 3),
                (_, -1) => agregar(índiceInicial, índiceFinal - 1),
                (0, _) => agregar(índiceInicial + 5, índiceFinal),
                (_, _) => agregar(índiceInicial, índiceFinal),
            };

你真的想在你的用例中使用 switch 表达式吗,传统的方式要好得多。

所有建议的解决方案,如委托、丢弃都是解决方法。

您试图错误地使用 switch 表达式。