简述
不可能的。 在 C# 8
中,switch expression
不能返回 void
。 它必须返回一个值,并且这个值必须被使用(赋给变量、作为方法参数传递、作为方法的返回结果等)。但是有一种解决方法。我们可以编写一个返回 delegate
的 switch expression
(例如类型为 Action
),然后立即调用它:
(stringValue switch
{
"Add" => (Action) Add,
"Subtract" => Subtract,
_ => throw new ArgumentOutOfRangeException()
})();
这种方法也适用于表达式主体的方法
。这是演示。
解释
这可行吗?
在C# 8
中不可以。这个限制在C#规范
中有描述。
让我们参考C#规范
。从页面递归模式匹配 - 开关表达式
和语句
,我们可以了解到:
-
switch_expression
不允许作为 expression_statement
。
-
expression_statement
评估给定的表达式。如果有,表达式计算的值将被丢弃。
从这两个语句我们可以得出结论:在 expression_statement
的上下文中不能使用 switch_expression
,其结果值不能被丢弃。结果值必须被使用,例如,它必须被赋值给一个变量,作为方法的参数传递或作为方法的返回值返回。因此编译器会报错指出无法将 switch expression
用作语句。
如果我们只需要在字符串值上进行切换并执行不返回任何内容(没有返回类型/void)的方法,应该如何处理?我想到了某种形式的 Func,但不确定具体的语法。
我们可以使用下面的方法:编写一个返回委托
的switch expression
并立即调用它。例如:
(stringValue switch
{
"Add" => (Action) Add,
"Subtract" => Subtract,
_ => throw new ArgumentOutOfRangeException()
})();
这种方法也可以用来声明 表达式体成员
:
private static void Demo(string str) =>
(str switch
{
"Add" => (Action) Add,
"Subtract" => Subtract,
_ => throw new ArgumentOutOfRangeException()
})();
这里是完整的示例。
在我看来,这种解决方法看起来很丑,个人更喜欢使用switch-case
或if-else
而不是这样的构造。
感谢l33t的评论。他指出,使用这种方法会导致每个case表达式
遭受非常昂贵的委托分配(在.NET 5
中验证)。因此,这是不使用此方法并更喜欢使用switch-case
或if-else
的另一个原因。
也许在将来的C#
版本中,这种限制将被放宽(请参见此链接):
switch_expression
不允许作为expression_statement
。
我们正在考虑在将来的修订版中放宽这一点。
但是我没有在csharplang repo
中找到合适的提案。
case
表达式都将受到非常昂贵的委托分配(在.NET 5中已经验证)。 - l33t