Acrotygma
Acrotygma

Reputation: 2569

Using switch statement for ranges

I'm trying to map a certain wind speed (measured in meters per second) to the appropriate label, taken from http://www.windfinder.com/wind/windspeed.htm. For this, I'd like to use switch statements, however I'm not sure how to do this in C#.

In ActionScript, it was possible using switch blocks, I've also seen it in Clang.

// ActionScript 3
switch(true) {
    case: mps >= 0 && <= 0.2
        return WindSpeedLabel.Calm; break;
    ...
    case else:
        WindSpeedLabel.ShitHittingTheFan;
}

// Clang
switch(mps) {
    case 0 ... 0.2:
        return WindSpeedLabel.Calm;
    ...

I'm aware it's possible using if/else statements, however with about 13 different ranges, I would appreciate a more readable solution.

Upvotes: 1

Views: 370

Answers (2)

KyleMit
KyleMit

Reputation: 30067

Update - Relational Patterns added in C#9

In a relational pattern, you can use any of the relational operators <, >, <=, or >=.
The right-hand part of a relational pattern must be a constant expression

Here's an example using ranges in a switch expression (Demo in .NET Fiddle):

var season = DateTime.Today.Month switch
{
    >= 3 and < 6 => "spring",
    >= 6 and < 9 => "summer",
    >= 9 and < 12 => "autumn",
    12 or (>= 1 and < 3) => "winter",
    _ => ""
};

Further Reading

Upvotes: 2

David
David

Reputation: 10708

Switch statements according to MSDN,

Each case label specifies a constant value. The switch statement transfers control to the switch section whose case label matches the value of the switch expression

Thus, you cannot specify a range, and when working with Doubles, the case of rounding and slight inaccuracies will make exact matches a poor choice at best.

UPDATE: If you want readability, the best I can offer is single lines and possibly hand alignment

if(mps >= 0 && <= 0.2) return WindSpeedLabel.Calm;
else if(mps <= 0.4)    return WindSpeedLabel.Gusty;
...
else                   return WindSpeeLabel.HurricaneForce5;

Note the above code does not use a minimum range after the first statement - this is prevent slight rounding errors from causing a given wind speed to fall through. This is because doubles on the hardware levels store using binary and occaisionally have a small degree of error, resulting in 0.2 coming into the runtime as 0.200000000000000001 or 0.1999999999999999 - while rare, this can cause behavior completely inconsistent with our human-perceived notion of the numbers, and makes double testing something we could imply from the previous statement slightly risky.

if you absolutely MUST have a Switch statement, you could render your wind speed as a string or round it.

switch((int)(mps * 10))
{
    case 0:
    case 1:
    case 2:
        return WindSpeedLabel.Calm;
        break;
}

Upvotes: 3

Related Questions