C# 8 switch expression for void methods(void 方法的 C# 8 开关表达式)
问题描述
我知道返回值的方法或属性匹配的 C# 8
switch 表达式
语法.但是如果我们只需要打开一个字符串值并执行一个什么都不返回的方法(没有返回类型/void),那么我们该怎么做呢?我正在考虑某种形式的 Func 但不确定确切的语法.我知道我们可以使用常规 case 语句以旧方式做到这一点,但试图看看我们是否可以使用新语法实现同样的效果.
这是问题的例子
开关(字符串值){案例添加":添加();休息;案例减":减();休息;}
可能是这样的:
字符串值开关{添加"=>添加(),减"=>减去()}//但这抱怨需要在左侧为此赋值
这可能吗?
TL;DR
不可能.在C# 8
switch expression
不能返回void
.它必须返回一个值,并且必须使用该值(分配给变量,作为参数传递给方法,作为方法的结果返回等).但是有一个解决方法.我们可以编写一个 switch 表达式
,它返回一个 delegate
(例如 Action
类型),然后立即调用它:
(stringValue 开关{添加"=>(行动)添加,减"=>减去,_ =>抛出新的 ArgumentOutOfRangeException()})();
这种方法也可以与表达式主体方法
一起使用.这是演示.
说明
<块引用>这可能吗?
在 C# 8
中这是不可能的.C# 规范
中描述了此限制.
让我们参考C#规范
.从页面 递归模式匹配 - 切换表达式
和 Statements
我们可以了解到:
- <块引用>
switch_expression
不允许作为expression_statement
. - <块引用>
expression_statement
计算给定的表达式.表达式计算的值(如果有)将被丢弃.
从这两个语句我们可以得出,switch_expression
不能在expression_statement
的上下文中使用,其结果值cannot 被丢弃.必须使用结果值,例如,它必须分配给变量、作为参数传递给方法或作为方法的结果返回.因此编译器抱怨 switch 表达式
不能用作语句.
<块引用>
如果我们只需要打开一个字符串值并执行一个方法什么都不返回(没有返回类型/void),我们该怎么做呢?我是正在考虑某种形式的 Func,但不确定确切的语法.
我们可以使用下一种方法:编写一个返回 delegate
的 switch 表达式
,然后立即调用它.例如:
(stringValue 开关{添加"=>(行动)添加,减"=>减去,_ =>抛出新的 ArgumentOutOfRangeException()})();
这个方法也可以用来声明表达式体成员
:
private static void Demo(string str) =>(str开关{添加"=>(行动)添加,减"=>减去,_ =>抛出新的 ArgumentOutOfRangeException()})();
这里是完整示例.
在我看来,这样的解决方法看起来很丑陋,我个人更喜欢使用 switch-case
或 if-else
而不是这样的构造.
感谢l33t的评论.他指出,使用这种方法会导致每个case expression
遭受非常昂贵的委托分配(在 .NET 5
中验证).所以还有一个理由不使用这种方法,而是更喜欢使用 switch-case
或 if-else
.
可能会在未来版本的 C#
中放宽此限制(查看此链接):
switch_expression
不允许作为 expression_statement
.
我们正在考虑在未来的修订中放宽这一点.
但我在 cshaplang repo中没有找到合适的提案代码>.
I'm aware of the C# 8
switch expression
syntax for methods that return a value or for property matching. But if we just need to switch on a string value and execute a method that returns nothing (no return type/void), then how do we go about it? I am thinking some form of Func but not sure of the exact syntax. I know we can do it the old way with regular case statements but was trying to see if we can achieve the same with the newer syntax.
Here's the example of the problem
switch (stringvalue)
{
case "Add": Add(); break;
case "Subtract": Subtract(); break;
}
could be like:
stringvalue switch
{
"Add" => Add(),
"Subtract" => Subtract()
}
// but this complains that there needs to be assignment on left side for this
Is this possible?
TL;DR
It is not possible. In C# 8
switch expression
cannot return void
. It must return a value and this value must be consumed (assigned to a variable, passed as an argument to a method, returned as a result of a method, etc.). But there is a workaround. We can write a switch expression
that returns a delegate
(of type Action
, for example) and then immediately invokes it:
(stringValue switch
{
"Add" => (Action) Add,
"Subtract" => Subtract,
_ => throw new ArgumentOutOfRangeException()
})();
Such approach also can be used with expression bodied methods
. Here is demo.
Explanation
Is this possible?
In C# 8
it is not possible. This limitation is described in C# specification
.
Lets refer to C# specification
. From pages Recursive Pattern Matching - Switch Expression
and Statements
we can learn that:
-
The
switch_expression
is not permitted as anexpression_statement
. -
An
expression_statement
evaluates a given expression. The value computed by the expression, if any, is discarded.
From these two statements we can conclude that switch_expression
cannot be used in the context of expression_statement
, and its result value cannot be discarded. The result value must be used, for example, it must be assigned to a variable, passed to a method as an argument or returned as a result of a method. Therefore compiler complains that switch expression
cannot be used as a statement.
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.
We can use the next approach: write a switch expression
that returns a delegate
and then immediately invokes it. For example:
(stringValue switch
{
"Add" => (Action) Add,
"Subtract" => Subtract,
_ => throw new ArgumentOutOfRangeException()
})();
This approarch also can be used to declare expression bodied members
:
private static void Demo(string str) =>
(str switch
{
"Add" => (Action) Add,
"Subtract" => Subtract,
_ => throw new ArgumentOutOfRangeException()
})();
Here is complete sample.
In my opinion such workaround looks ugly and personally I would prefer to use switch-case
or if-else
instead of such construction.
Thanks to l33t's comment. He pointed out that using such approach would cause each case expression
suffer from very costly delegate allocation (verified in .NET 5
). So it is one more reason not to use this approach and prefer to use switch-case
or if-else
.
May be in future version of C#
this limitation will be relaxed (see this link):
The
switch_expression
is not permitted as anexpression_statement
.We are looking at relaxing this in a future revision.
But I haven't found an appropriate proposal in csharplang repo
.
这篇关于void 方法的 C# 8 开关表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:void 方法的 C# 8 开关表达式
基础教程推荐
- MS Visual Studio .NET 的替代品 2022-01-01
- SSE 浮点算术是否可重现? 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01
- 将 XML 转换为通用列表 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- 如何激活MC67中的红灯 2022-01-01
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01