Evaluate Expressions in Switch Statements in C#

Viewed 111588

I have to implement the following in a switch statement:

switch(num)
{
  case 4:
    // some code ;
    break;
  case 3:
    // some code ;
    break;
  case 0:
    // some code ;
    break;
  case < 0:
    // some code ;
    break;
}

Is it possible to have the switch statement evaluate case < 0? If not, how could I do that?

13 Answers

you can do this

switch (mark)
{
    case int n when n >= 80:
        Console.WriteLine("Grade is A");
        break;

    case int n when n >= 60:
        Console.WriteLine("Grade is B");
        break;

    case int n when n >= 40:
        Console.WriteLine("Grade is C");
        break;

    default:
        Console.WriteLine("Grade is D");
        break;
}

In a twist of C# fate, this has come all the way back around. If you upgrade to C# 9.0, your original switch statement will now compile! C#9.0 has added Relational patterns to pattern matching in general, which includes switch statements.

You can now do some really funky stuff, like this:

      var num = new Random().Next();
      
      switch(num)
      {
        case < 0:
          // some code ;
          break;
        case 0:
          // some code ;
          break;
        case > 0 and < 10:
          // some code ;
          break;
        case > 20 or (< 20 and 15):
          // some code ;
          break;
      }

Note the use of literal 'and' and 'or' in the last case, to allow && and || type expressions to compile.

To use C# 9, make sure the XmlNode LangVersion is set to Latest or 9.0 in the csproj file, in a property group

e.g.

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <Platforms>AnyCPU;x86</Platforms>
    <Configurations>Debug;Release;Mock</Configurations>
    <LangVersion>Latest</LangVersion>
  </PropertyGroup>

Enter 2021.

var res = num switch
{
    4 => "It's four",
    3 => "It's three",
    0 => "It's zero",
    < 0 => "It's negative",
    _ => "It's something else"
};

Boom.

(To be fair, switch expressions are a C# 8.0 feature, so not really 2021. But still few people seem to know about it.)

What you could do is to use a delegate like this.

        var actionSwitch = new Dictionary<Func<int, bool>, Action>
        {
             { x => x < 0 ,     () => Log.Information("less than zero!")},
             { x => x == 1,     () => Log.Information("1")},
             { x => x == 2,     () => Log.Information("2")},
             { x => x == 3,     () => Log.Information("3")},
             { x => x == 4,     () => Log.Information("4")},
             { x => x == 5,     () => Log.Information("5")},
        };

        int numberToCheck = 1;

        //Used like this
        actionSwitch.FirstOrDefault(sw => sw.Key(numberToCheck)).Value();

Just swap out what you wan´t to perform where the Log.Information("x") is and you have your "switch" statement.

You will need to some error handling if you check for a key that is "found" by the Func.

If you like to see the Func version of the switch I just wrote a blog post with Switch example chapter.

But if you can use C# 7 it will give you better switch capabilities.

I've run into the following pattern recently, and while I abhor it, I can't argue that it's not practical:

switch(0)
{
  case 0 when x < 0:
    ...
    break;
  case 0 when a > 5 && x == 0:
    ...
    break;
}

The use of dummy expressions ((0) in the switch, and case 0) is absolutely terrible, and I'd hate for it to become an idiom, but hey - it's concise and very clear. For sure it's not some hack that completely obscures the meaning and needs arcane knowledge, but C# would do well to obviate the need for it. I'd like the following to be legal:

switch                   // maybe () here, if the grammar would demand
{
  case when x < 0:       // I like the case to stay
    ...
  case when a > 5 && x == 0:
    ...
}
Related