30

我知道C# 8 switch expression返回值或属性匹配的方法的语法。但是如果我们只需要打开一个字符串值并执行一个什么都不返回的方法(没有返回类型/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

这可能吗?

4

3 回答 3

31

TL;博士

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

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

这种方法也可以与expression bodied methods. 这是演示


解释

这可能吗?

C# 8它是不可能的。此限制在 中进行了描述C# specification

让我们参考C# specification。从页面中Recursive Pattern Matching - Switch ExpressionStatements我们可以了解到:

  • switch_expression不允许expression_statement作为.

  • Anexpression_statement计算给定的表达式。表达式计算的值(如果有)将被丢弃。

从这两个陈述我们可以得出结论,switch_expression不能在 的上下文中使用expression_statement,并且它的结果值不能被丢弃。必须使用结果值,例如,它必须分配给变量、作为参数传递给方法或作为方法的结果返回。因此编译器抱怨switch expression不能用作语句。


如果我们只需要打开一个字符串值并执行一个什么都不返回的方法(没有返回类型/void),我们该怎么做呢?我正在考虑某种形式的 Func 但不确定确切的语法。

我们可以使用下一种方法:编写一个switch expression返回 adelegate然后立即调用它的 a。例如:

(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()
     })();

这是完整的示例

在我看来,这种解决方法看起来很难看,我个人更愿意使用switch-caseif-else代替这种结构。

感谢 l33t 的评论。他指出,使用这种方法会导致每个人都case expression遭受非常昂贵的委托分配(在 中验证.NET 5)。因此,不使用这种方法并更喜欢使用switch-caseor是另一个原因if-else


可能在以后的版本中C#这个限制会放宽(见这个链接):

switch_expression不允许expression_statement作为.

我们正在考虑在未来的修订中放宽这一点。

但我没有在csharplang repo.

于 2020-05-27T08:42:03.960 回答
2

正如伊利亚尔告诉你的那样,这是不可能的。我有时使用的一种解决方法是添加一个始终返回 true 的本地函数,并且我在 switch 分配中使用了一个丢弃字符。我发现这个解决方法比使用代表的方法更清晰一些。

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

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

然后你会这样称呼它:

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

我认为这种方法有一些用例。例如,如果你想在 switch 中使用元组模式,它会比许多 annidated ifs 更具可读性。这是我正在使用的代码,我认为这种方法比 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),
            };
于 2020-10-05T20:44:22.840 回答
-3

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

所有建议的解决方案(例如代表、丢弃)都是解决方法。

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

于 2020-10-14T18:44:39.723 回答