tags:

views:

338

answers:

7

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?

+18  A: 

You can't - switch/case is only for individual values. If you want to specify conditions, you need an "if":

if (num < 0)
{
    ...
}
else
{
    switch(num)
    {
        case 0: // Code
        case 1: // Code
        case 2: // Code
        ...
    }
}
Jon Skeet
Thank you very much
priyanka.sarkar
or even switch(num) { case 0: case 1: default: if (num < 0) {..} }
roe
@roe: Yes, I considered giving that form too. Ran out of time though :)
Jon Skeet
+3  A: 

You will have to use if, wether you want or not. Switch is only capable of comparing your value to constant values.

Maximilian Mayerl
Not true -- you can use a ternary operator to consolidate the less-than-zero case into a single value, and evaluate that in the switch.
Charles Duffy
This is true. It's just a restriction of the language. You can actually do this in VB.Net, as well as other things like using value ranges. Like C#, if has to compare against literal value, but there are more compare operations available.
Andy McCluggage
Really Charles? Interesting. I did not know that.
Andy McCluggage
Just to be nit-picky, saying "constant values (literals)" is an error. You were doing great right up until the parenthetical. The parenthetical implies that "literals" and "constant values" are *synonyms* when in fact literal constants are a *subset* of constant values. All literals are constants, but not all constants are literals. The switch statement requires constants, but does not require literals.
Eric Lippert
Thanks for clarifying, I'll edit my answer.
Maximilian Mayerl
@Andy - yes, the VB "select/case" is much more powerful and flexible than the C# "switch/case". Although I see that you can now do a "switch" on strings in C# - couldn't do that in C/C++, IIRC.
Tom Bushell
+4  A: 

If your num can't be less than zero:

public int GetSwitch(int num) { return num < 0 ? -1 : num; }
switch(GetSwitch(num))
{
case 4: // some code ; break;
case 3:// some code ; break;
case 0: // some code ; break;
case -1 :// some code ; break;
}

If it can, use some other "non-existent" number such as int.MinValue.

queen3
That's what I was going to suggest -- but why put the ternary in a different function?
Charles Duffy
interesting solution +1, although I personally feel the extra function call clutters the view a bit, `switch (num < 0 ? -1 : num)` just feels more explict.
roe
I'm a big follower of SRP and DRY - so even unconsciously I separate one behavior from another unrelated behavior. GetSwitch(), for example, can be reused, and what if you need two switches - do you copy/paste your ternary into there? I don't consider copy/pasting a good practice.
queen3
Just name it GetMeaningfulSwitchName() (e.g. GetOrderTypeSwitch) and this will make more sense. Maybe even put this into the entity itself, like Order.GetTypeRank().
queen3
DRY is of course good, however actually repeating "GetSwitch(num)" is more repeating than num<0?-1:num (which is two characters less)... :) All jokes aside, I think in this case, not having the result of GetSwitch immediately deducable (e.g. if you're using it somewhere else as well) hurts more than helps. But that's only MHO.
roe
Jokes aside, what is going to happen if your switch logic changes (e.g. -1 is now a valid number) and you need to use int.MinValue (or -2) instead of -1 as the switch number? Are you going to search and replace all the hard-coded switches? I really hate the copy/pasted code, and this is one of the reasons why - it's a nightmare to maintain. Another reason - it is not clear to read. GetOrderRankSwitch() can be _read_, while ternary doesn't tell anything. And you can't track in the sources (called by).
queen3
And by the way, the "num<0?-1:num" doesn't even contain spaces, if we talk about characters (which is not what DRY is about). Also, it seems that there're people who doesn't get the idea that function name expresses its intent, while immediate inline code rarely does. Getting this comment up-voted 2 times means more "maintenance from hell" work for some people.
queen3
+3  A: 

The only way I could think of (and I really don't recommand it), would be as follows:

int someValue;

switch (Math.Max(someValue, -1))
{
    case -1:
        // will be executed for everything lower than zero.
        break;

    case 0:
       // will be executed for value 0.
       break;

    case 1:
       // will be executed for value 1.
       break;

    default:
       // will be executed for anything else.
       break;
}
Oliver Hanappi
Why am I getting downvoted?
Oliver Hanappi
Why not just Math.Max(someValue, -1) ? Then he doesn't need to worry about the +1 offset...
JustLoren
Didn't downvote you but I think it's just Bad Style.
chakrit
I think it's bad style too, so I stated in my answer that i really don't recommand that way. And Math.Max(x, -1) is really better than 0.
Oliver Hanappi
@Oliver: probably because your code is pretty close to obfuscation. It's not immediately visible what's happening here. The other solutions provided here are much more readable.
Joachim Sauer
+9  A: 

You could do something like this at the end of your switch statement:

default:
    if(num < 0)
    {
        ... // Code
    }
    break;
tbreffni
+2  A: 

The other way around would be possible also (relating to Jon Skeet's answer):

switch(num)
{
  case a:
      break;
  default:
      if( num < 0 )
      {}
   break;
}
StampedeXV
A: 

You cannot use comparisons in switches like you could in VB, you have 2 options here, replace the value you switch on with a known value and use that or - if you mean all other cases - you can use the default clause:

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

Note that this does not exactly like you asked for: any values other than 0,3,4 will end up in the deafult: clause.

rsp