34

Switch expressions were introduced in C# 8. There's plenty of places in codebases, which may be rewritten in this new style.

For example, I have some code, which is used for parsing packets from a stream of bytes:

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

The problem is - it can't be converted to a switch expression like

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

The first thing that got in my mind was to use a Func<>, which compiles:

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

F# already allows code with multiple statements in each branch:

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

Now I'm stuck using switch-statements, but is there any option to write this as a switch-expression without any weird hacks?

13
  • 1
    Nitpick: "expression" doesn't have that many S's in it. Commented Jan 24, 2020 at 4:32
  • 2
    so suggest an edit? Commented Jan 24, 2020 at 5:12
  • Personally, I would convert to a switch statement in such cases. That said, C# LDM is discussing some options to allow statements inside switch expressions and possibly more generally ("expression blocks"). Here's the proposal we most recently reviewed: github.com/dotnet/csharplang/issues/3086 Commented Jan 24, 2020 at 5:13
  • 3
    The switch expression is not meant to replace the switch statement. It serves a different purpose. It will not handle multiple statements, and it shouldn't, because you're just switching on a value to get the right single expression evaluated. So you're entirely right, getting the switch expression to handle multiple statements is a pain, in pretty much the same way as using a hammer to split a plank in two is. Commented Jan 24, 2020 at 8:57
  • 1
    @JL0PD you can use local functions to combine multiple statements into one function that can be used in any expression, including switch expressions Commented Jan 24, 2020 at 10:14

2 Answers 2

37

Your only supported choice is the func like you did. See [this article][1] for more information. His example:

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

Just because switch expressions are new doesn't mean they are the best for all use cases. They are not designed to contain multiple commands.

Edit: I suppose you could also simply call external functions instead of making anonymous ones. [1]: https://alexatnet.com/cs8-switch-statement/

Sign up to request clarification or add additional context in comments.

3 Comments

"It's not designed to contain multiple commands." and is certainly not more readable.
@Jeroen van Langen that's the understatement of the year.
this is actually very similar to javascript event functions. They are designed for a single call but you can embed a function in them.
6

With:

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

its looks like:

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

or:

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

2 Comments

Generally, answers are much more helpful if they include an explanation of what the code is intended to do, and why that solves the problem without introducing others.
it's also basically ripping off my answer

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.