3

I haven't a living clue how to write this in c#. I know how to do it in Delphi.

This is how I would do it in Delphi:

Case Total of
    80..100 : ShowMessage ('You got an A!');
    60..79  : ShowMessage ('You got a B!');
    50..59  : ShowMessage ('You got a C!');
    40..49  : ShowMessage ('You got a D!');
    0..39   : ShowMessage ('You got an E...');
  end;

I have read tutorials for this, but I wouldn't know how to use/write it in the way I need it.

Here's my version in c#:

switch (Total) //'Total' is a bunch of Integers divided together to get a Percentage
            {
             case 80..100: //Where 80% to 100% would achieve an A
            {
             MessageBox.Show("You got an A!");
            }
             case 60..79: //Where 60% to 79% would achieve a B
            {
             MessageBox.Show("You got a B!");
            }

Is this possible?

Thanks.

Aidan Quinn
  • 1,178
  • 4
  • 20
  • 33
  • 2
    This might be the best choice... http://stackoverflow.com/questions/11339191/switch-case-check-ranges-in-c-sharp-3-5 – tweellt Mar 15 '14 at 16:13
  • Check out my answer for two other solutions. Or if you really want to be fancy you can create you own switch class: http://community.bartdesmet.net/blogs/bart/archive/2008/03/30/a-functional-c-type-switch.aspx – KingOfHypocrites Mar 15 '14 at 16:51

9 Answers9

9

To express a range in a switch / case statement in C# you have to manually list out the cases

switch (Total) {
  case 80:
  case 81: 
  ...
  case 100:
    MessageBox.Show("you got an A");
    break;
  ...
}

For large ranges such as this though it may be better to just use a series of if statements

if (Total >= 80 && Total <= 100) { 
   MessageBox.Show("you got an A");
} else if (Total >= 70) { 
   MessageBox.Show("you got a B");
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
8

C# does not have a particularly flexible switch statement. This is intentional, options are limited to ensure that code generation is fast. C# has never been a language that hides execution cost. Runtime implementation is through a jump table, indexed by the switch() expression. Very fast, but not very flexible.

The alternative is an explicit if/else if chain. The exact same code that a VB.NET or Delphi compiler generates, but written by hand. Not terribly pretty, but effective enough:

if (Total < 0 || Total > 100) throw new ArgumentException("Not a valid grade");
if      (Total >= 80) ShowMessage ('You got an A!');
else if (Total >= 60) ShowMessage ('You got a B!');
else if (Total >= 50) ShowMessage ('You got a C!');
else if (Total >= 40) ShowMessage ('You got a D!');
else                  ShowMessage ('You got an E...');

This now also shows the cost associated with the code, there can be up to 6 comparisons on the Total value. If speed is essential and the range is limited then consider switching to a lookup table, a Dictionary<>. Not necessary here, ShowMessage() is an expensive method.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
3

AFAIK you can't do it natively in C# but if you want to do it with a switch, like you stated in your question, there is a workaround for that (for fixed ranges). Considering your interval of 20 by 20:

int interval= (value-1) / 20;
  switch (interval) 
 {
    case 0: // 1-20
         //Do stuffs
         break; 
    case 1: // 21-40
         //Do stuffs
         break; 
    // and so on
 }
Saverio Terracciano
  • 3,885
  • 1
  • 30
  • 42
  • This would be hard to maintain and is incorrect. Re-examine the original spec. – jdphenix Mar 15 '14 at 16:15
  • 1
    Considering the alternatives for a switch statement that would do the same, I don't think this would be harder to mantain than, say, listing out all the options. Of course I'd be more comfortable handling it in other ways but since the OP was interested in switch I suggested it this way. – Saverio Terracciano Mar 15 '14 at 16:19
  • Alternatives for doing the same? What do you mean? If you check with `if`, you do not have to code `if (Total == 80 || Total == 81 || total == 82 || Total == 83 || \* ... *\)`. And regarding the spec, the different ranges do not all have a difference of 20. – jdphenix Mar 15 '14 at 16:28
  • I meant alternative ways for doing it with switch, instead of nesting ifs. But you're right about the range, I didn't notice that they weren't fixed. – Saverio Terracciano Mar 15 '14 at 16:31
  • 1
    I like the idea behind it, but I'd prefer to just use value/10 (and no need to subtract 1), even though this results in more cases. – Brian Mar 17 '14 at 16:57
3

If it is supposed to be a switch then it should be like this:

switch(Total)
{
     case 100:
     case 99:
     //...
     case 80:
         MessageBox.Show("You got an A!");
         break;

     case 79:
     // ...
}

If it is okay to use if-statements I would recommend to do it like this:

if (Total < 0)
{
}
else if (Total < 40)
    MessageBox.Show("You got an E...")
else if (Total < 50)
    MessageBox.Show("You got a D!");
else if (Total < 60)
// etc.

Hop you could use this answer.

Casperah
  • 4,504
  • 1
  • 19
  • 13
2

You could use a switch/case statement by creating a very long case statement or an extension method that turned a range of numbers into a constant. But it's probably easier to use an if/else block.

Personally, I like the readability of Enumerable.Range slightly over >= and <=. However, it is a slower operation because you're creating an enumerable of ints everytime you do a comparison. You'll probably on notice performance issues when you get in the tens of thousands of grads though.

if(Enumerable.Range(80,100).Contains(Total))
{
    MessageBox.Show("You got an A!");
}
else if(Enumerable.Range(60, 79).Contains(Total))
{
    MessageBox.Show("You got a B!");
}
else if(Enumerable.Range(50, 59).Contains(Total))
{
    MessageBox.Show("You got a C!");
}
else if(Enumerable.Range(40, 49).Contains(Total))
{
    MessageBox.Show("You got a D!");
}
else if(Enumerable.Range(0, 39).Contains(Total))
{
    MessageBox.Show("You got an E...");
}
Steven Wexler
  • 16,589
  • 8
  • 53
  • 80
  • Okay... This will work, but it's "overcomplicated" I think. It would be better if you do this: `if (Total <= 100 && Total >= 80)` – joppiesaus Mar 15 '14 at 16:17
  • Well, I don't know why it was down voted - it does work - but it is still inefficient for such a simple task. – Casperah Mar 15 '14 at 16:18
  • @Casperah, I agree that is a bit inefficient. I really doubt the OP will notice performance problems from `Enumerable.Range` before he starts grading papers in the order of tens of thousands. I'll explain why it's slower than other options. @joppiesaus, I used Enumerable.Range because it's slightly more readable in my opinion than using lte and gte. – Steven Wexler Mar 15 '14 at 16:22
2

A solution to solve your problem is to do it like this.

switch (Total)
{
case 1: case 2: case 3:          
    // Do Something
    break;
case 4: case 5: case 6: 
    // Do Something
    break;
default:
    // Do Something
    break;
}

Multiple Cases in Switch:

Community
  • 1
  • 1
Erwin Kraan
  • 268
  • 3
  • 8
2

What about this?:

var s = "EEEEDCBBAAA";
var result = s[Total/10];
MessageBox.Show("you got a " + result);

Because Switch Statements Smells :)

Update

Didn't realize the a / an difference, but:

MessageBox.Show(string.Format("you got a{0} {1}", 
     result == "A" || result == "E" ? "n" : "", 
     result));
thepirat000
  • 12,362
  • 4
  • 46
  • 72
  • 1
    Err, just no. Case statements have their place, and this task is one of them. You've just taking what is usually good advice and used it to justify difficult to maintain code. Perhaps you could elaborate _why_ this solution is better than checking range in a series of `if`, `else if` statements. – jdphenix Mar 15 '14 at 16:25
  • @jdphenix Oh yeah! So difficult to maintain. Why don't you suggest a solution instead of downvoting all the solutions given? – thepirat000 Mar 15 '14 at 16:27
  • Why would I add an answer to a question that has four good solutions already. And it's a bit odd to assume the downvote is mine - your solution isn't dangerously wrong, it just breaks easily. – jdphenix Mar 15 '14 at 16:33
  • I'm not saying my solution is better. It's just a humble alternative solution :) – thepirat000 Mar 15 '14 at 16:34
2

Use an action lookup (like a command pattern)

static void Main(string[] args)
        {
            var theGrade = 89;
            var gradeLookup = new Dictionary<Func<int, bool>, Action>
                    { 
                        { x => x >= 90, () => ShowMessage("You got an A!") },
                        { x => x >= 80 && x < 90, () => ShowMessage("You got an B!") },
                    };

            gradeLookup.First(x => x.Key(theGrade)).Value();

            Console.ReadKey();
        }

        static void ShowMessage(string msg)
        {
            Console.WriteLine(msg);
        }

You can also simply divide by 10 to reduce the checks, but this would only work for some college scales:

 static void Main(string[] args)
        {
            var theGrade = 80;
            switch (theGrade / 10)
            {
                case 10:
                case 9:
                    ShowMessage("You got an A");
                    break;
                case 8:
                    ShowMessage("You got a B");
                    break;
                case 7:
                    ShowMessage("You got a C");
                    break;
                case 6:
                    ShowMessage("You got a D");
                    break;
                default:
                    ShowMessage("You got a F");
                    break;

            }

            Console.ReadKey();
        }
KingOfHypocrites
  • 9,316
  • 9
  • 47
  • 69
1

What about this code:

private string GetTotalCode(int total) {
  if (Total >= 80 && Total <= 100)
    return "A"
  if ...
}

and then simplify switch:

switch (GetTotalCode(Total)) {
  case "A": 
    MessageBox.Show("you got an A");
    break;
  ...
}
Pavel Hodek
  • 14,319
  • 3
  • 32
  • 37