【问题标题】:Multiple statements in a switch expression: C# 8switch 表达式中的多个语句:C# 8
【发布时间】:2020-05-10 09:56:00
【问题描述】:

Switch 表达式是在 C# 8 中引入的。代码库中有很多地方可以用这种新风格重写。

例如,我有一些代码,用于从字节流中解析数据包:

switch (command)
{
    case Command.C1:
        return new P1();
    case Command.C2:
        return new P2();
    default:
        stream.Position++;
        return null;
}

问题是 - 它不能转换成类似的 switch 表达式

return command switch
{
    Command.C1 => new P1(),
    Command.C3 => new P2(),
    _ => { stream.Position++; return null; }
};

我首先想到的是使用Func<>,它可以编译:

return command switch
{
    Command.C1 => new P1(),
    Command.C3 => new P2(),
    _ => new Func<AbstractPacket>(() => { stream.Position++; return null; })()
};

F# 已经允许代码在每个分支中包含多个语句:

match command with
| Command.C1 -> Some(P1() :> AbstractPacket)
| Command.C2 -> Some(P2() :> AbstractPacket)
| _ ->
    stream.Position <- stream.Position + 1
    None

现在我无法使用 switch 语句,但是有没有任何选项可以将它写为 switch 表达式而没有任何奇怪的黑客攻击?

【问题讨论】:

  • Nitpick:“表达式”中没有那么多 S。
  • 所以建议编辑?
  • 就个人而言,在这种情况下,我会转换为switch 声明。也就是说,C# LDM 正在讨论一些选项以允许在 switch 表达式中使用语句,并且可能更普遍(“表达式块”)。这是我们最近审查的提案:github.com/dotnet/csharplang/issues/3086
  • switch 表达式并不意味着替换 switch 语句。它有不同的用途。它不会处理多个语句,也不应该处理,因为您只是打开一个值来评估正确的 single 表达式。所以你是完全正确的,让 switch 表达式来处理多个语句是一件很痛苦的事情,就像用锤子把一块木板一分为二一样。
  • 我的评论放在一边,你到底想问什么?您是否有一个必须使用 switch 表达式但必须有语句的用例?或者这只是一个学术问题,比如“我怎样才能颠覆一个 switch 表达式来代替一个 switch 语句”?基本上,你想解决哪个问题?

标签: c# c#-8.0 switch-expression


【解决方案1】:

您唯一支持的选择就是您所做的 func。请参阅this article 了解更多信息。他的例子:

var result = operation switch
{
"+" => ((Func<int>)(() => {
    Log("addition");
    return a + b;
}))(),
"-" => ((Func<int>)(() => {
    Log("subtraction");
    return a - b;
}))(),
"/" => ((Func<int>)(() => {
    Log("division");
    return a / b;
}))(),
_ => throw new NotSupportedException()
};

仅仅因为 switch 表达式是新的并不意味着它们是所有用例的最佳选择。它们并非旨在包含多个命令。

【讨论】:

  • “它不是为包含多个命令而设计的。” 而且肯定不会更易读。
  • @Jeroen van Langen 这是今年的轻描淡写。
  • 这实际上与javascript事件函数非常相似。它们是为单次调用而设计的,但您可以在其中嵌入一个函数。
【解决方案2】:

与:

TRes Call<TRes>(Func<TRes> f) => f();

它看起来像:

return command switch {
  Command.C1 => new P1(),
  Command.C3 => new P2(),
  _ => Call(() => { stream.Position++; return null; }),
};

或:

var result = operation switch {
  "+" => Call(() => {
    Log("addition");
    return a + b;
  }),
  "-" => Call(() => {
    Log("subtraction");
    return a - b;
  }),
  "/" => Call(() => {
    Log("division");
    return a / b;
  }),
  _ => throw new NotSupportedException(),
};

【讨论】:

  • 一般来说,如果答案包含对代码的用途的解释,以及为什么在不介绍其他人的情况下解决问题的原因,答案会更有帮助。
  • 这也基本上是在抄袭我的答案
猜你喜欢
  • 1970-01-01
  • 2011-03-28
  • 2015-09-21
  • 1970-01-01
  • 2011-05-01
  • 2016-01-01
  • 2014-11-06
  • 2019-11-17
相关资源
最近更新 更多