110

I can't figure out how to use switches in combination with an enum. Could you please tell me what I'm doing wrong, and how to fix it? I have to use an enum to make a basic calculator.

public enum Operator
{
    PLUS, MINUS, MULTIPLY, DIVIDE
}

public double Calculate(int left, int right, Operator op)
{

    int i = (int) op;

    switch(i)
    {
        case 0:
        {
            return left + right;
        }

        case 1:
        {
            return left - right;
        }

        case 2:
        { 
            return left * right;
        }

        case 3:
        {
            return left / right;
        }

        default:
        {
            return 0.0;
        }
    }
}

The end result should be something like this:

Console.WriteLine("The sum of 5 and 5 is " + Calculate(5, 5, PLUS))
Output: The sum of 5 and 5 is 10

Could you guys please tell me how I'm messing up?

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
yesman
  • 7,165
  • 15
  • 52
  • 117

11 Answers11

164

You don't need to convert it

switch(op)
{
     case Operator.PLUS:
     {
        // your code 
        // for plus operator
        break;
     }
     case Operator.MULTIPLY:
     {
        // your code 
        // for MULTIPLY operator
        break;
     }
     default: break;
}

By the way, use brackets

Jenna Leaf
  • 2,255
  • 21
  • 29
J.Starkl
  • 2,183
  • 1
  • 13
  • 15
  • 11
    @J.Starkl Well that's a matter of opinion, I think :-) – Stephan Bauer Feb 28 '13 at 13:06
  • 1
    @StephanBauer: Yes, it is :-) – J.Starkl Feb 28 '13 at 13:08
  • More of an indent man, myself =) Strangely enough, that's the only thing I don't put braces on. Go figure! – Kenneth K. Feb 28 '13 at 13:12
  • 29
    If you ever introduce a new variable for use in a single case, you do of course need to use brackets. And at that point my OCD kicks in and I need to make all the cases look the same by adding brackets to them. (In all seriousness, I use brackets in switch statements because I use them for blocks everywhere else.) – Matthew Watson Feb 28 '13 at 13:24
  • @MatthewWatson Great! Thanks for mentioning that point with variabloes for a single case - never thought of that :-) – Stephan Bauer Mar 01 '13 at 10:54
  • C# can have multi-line blocks without brackets since all must terminate with a return or break, goto or have no code at all. Fall-through is not allowed outside of these options: http://stackoverflow.com/questions/174155/switch-statement-fallthrough-in-c – Rafe Apr 29 '14 at 15:42
  • 11
    Yes, but if you use them everywhere -no pitfalls -consistent code -improved readability -simpler maintenence/extension -best practice (get used to them) – J.Starkl Apr 30 '14 at 11:20
  • about the readability - I find python and haskell code way easier to read than c# or java – IARI Jun 03 '16 at 05:49
  • Note that the brackets isn't related to the switch/case: You can add brackets anywhere you want to separate variables. – Matthieu Charbonnier Nov 26 '17 at 20:55
  • Switch case enables you to reuse the same code block for multiple cases. If you do - make sure to not use brackets. – Nadav Oct 12 '19 at 08:54
  • I think it's a bit odd that you use braces for every case (so they'll match) but...not for "default:"...heck default is even on the same line, not matching the other cases. Not exactly criticizing, just enjoying how different people define "consistent" in different ways. – tekHedd Mar 25 '20 at 17:54
33

Since C# 8.0 introduced a new switch expression for enums you can do it even more elegant:

public double Calculate(int left, int right, Operator op) =>
            op switch 
        {
            Operator.PLUS => left + right,
            Operator.MINUS => left - right,
            Operator.MULTIPLY => left * right,
            Operator.DIVIDE => left / right,
            _    =>  0
        }

Ref. https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8

Przemek Struciński
  • 4,990
  • 1
  • 28
  • 20
12

The correct answer is already given, nevertheless here is the better way (than switch):

private Dictionary<Operator, Func<int, int, double>> operators =
    new Dictionary<Operator, Func<int, int, double>>
    {
        { Operator.PLUS, ( a, b ) => a + b },
        { Operator.MINUS, ( a, b ) => a - b },
        { Operator.MULTIPLY, ( a, b ) => a * b },
        { Operator.DIVIDE ( a, b ) => (double)a / b },
    };

public double Calculate( int left, int right, Operator op )
{
    return operators.ContainsKey( op ) ? operators[ op ]( left, right ) : 0.0;
}
JustAndrei
  • 863
  • 4
  • 17
  • 3
    I think this is an example of where using var to declare the variable would be appropriate! – Chris Dunaway Feb 28 '13 at 16:09
  • 1
    Var cannot be used outside the method body. – JustAndrei Feb 28 '13 at 20:33
  • Oh yes, I missed that it was declared outside of the method. – Chris Dunaway Feb 28 '13 at 23:46
  • You can use `using OperatorsDict = Dictionary>` and then use `OperatorsDict` instead – Adassko Oct 15 '13 at 12:19
  • @JustAndrei - (I know it is an old post) Why is this method better than switch - is it faster ? or is it preference ? I would like to know not for arguments sake but better coding - I have always used switch but never thought to use a dictionary function. Certainly should not be in a serializable object.. of course Adassko's comment kind of makes my thoughts on a memory issue go away. – Stix Nov 20 '15 at 19:46
  • 2
    1. Separation of configuration and logic: your code becomes short and easy to read. Your configuration reads like a table, what is easy as well. 2. Unlike switch, Dictionary internally uses a hashtable for fast lookup, what becomes significant when there are many cases. Sometimes programmers put the most used item at the end of the switch and have problems with performance. 3. Once the configuration is extracted from the code, now you can make a lot of great things: – JustAndrei Nov 22 '15 at 15:53
  • 1
    A. Move it from the code to an external source, e.g. configuration file or database. B. Dynamically modify configuration upon your needs, right while program execution. C. Create a plugin system, so that your configuration is extended by modules. D. Although Dictionary already helps to search the key faster, you can make it even better by customizing the way you lookup the operation. Once I implemented such a replacement for the switch, which accumulated case usage statistics during program execution, and periodically re-arranged the list of cases so that the most popular one became the first. – JustAndrei Nov 22 '15 at 15:54
  • 2
    I'd like to see one reliable piece of evidence that Dictionary look-up is faster than 'Switch with Enums. – BillW Mar 31 '16 at 17:04
  • @BillW You won't, because it isn't. Using a dictionary for this is a simply dreadful design choice. – 0b101010 Mar 26 '21 at 14:53
3

You should not cast to integer. And for the division, you need to cast left to double first, if not you will be doing an integer divide.

public enum Operator
{
    PLUS, MINUS, MULTIPLY, DIVIDE
}

public double Calculate(int left, int right, Operator op)
{
    double sum = 0.0;

    switch(op)
    {
       case Operator.PLUS:
       sum = left + right;
       return sum;

       case Operator.MINUS:
       sum = left - right;
       return sum;

       case Operator.MULTIPLY:
       sum = left * right;
       return sum;

       case Operator.DIVIDE:
       sum = (double)left / right;
       return sum;

       default:
       return sum;
   }

   return sum;
}
Jeow Li Huan
  • 3,758
  • 1
  • 34
  • 52
3

simply don't cast to int

 switch(operator)
    {
       case Operator.Plus:
       //todo
burning_LEGION
  • 13,246
  • 8
  • 40
  • 52
3

No need to convert. You can apply conditions on Enums inside a switch. Like so,

public enum Operator
{ 
    PLUS,
    MINUS,
    MULTIPLY,
    DIVIDE
}

public double Calculate(int left, int right, Operator op)
{
    switch (op)
    {
        case Operator.PLUS: return left + right; 
        case Operator.MINUS: return left - right; 
        case Operator.MULTIPLY: return left * right;
        case Operator.DIVIDE: return left / right;
        default: return 0.0; 
    }
}

Then, call it like this:

Console.WriteLine("The sum of 5 and 5 is " + Calculate(5, 5, Operator.PLUS));
Kent Aguilar
  • 5,048
  • 1
  • 33
  • 20
  • This answer illustrates perfectly the right time to break the convention and use 1) early return from a function and 2) putting the case on the same line as the code. – tekHedd Mar 25 '20 at 17:58
2
 public enum Operator
    {
        PLUS, MINUS, MULTIPLY, DIVIDE
    }

    public class Calc
    {
        public void Calculate(int left, int right, Operator op)
        {

            switch (op)
            {
                case Operator.DIVIDE:
                    //Divide
                    break;
                case Operator.MINUS:
                    //Minus
                    break;
                case Operator.MULTIPLY:
                    //...
                    break;
                case Operator.PLUS:
                    //;;
                    break;
                default:
                    throw new InvalidOperationException("Couldn't process operation: " + op);
            }
        }
    }
omer schleifer
  • 3,897
  • 5
  • 31
  • 42
1

All the other answers are correct, but you also need to call your method correctly:

Calculate(5, 5, Operator.PLUS))

And since you use int for left and right, the result will be int as well (3/2 will result in 1). you could cast to double before calculating the result or modify your parameters to accept double

Scott Baker
  • 10,013
  • 17
  • 56
  • 102
Stephan Bauer
  • 9,120
  • 5
  • 36
  • 58
1

In case you don't want to use return statement for each case, try this:

Calculate(int left, int right, Operator op)
{
   int result = 0;
   switch(op)
   {
        case Operator.PLUS:
        {
            result = left + right;;  
        }
        break;
        ....
   }

   return result;
}
Martin
  • 3,396
  • 5
  • 41
  • 67
  • Unclear how this makes the code more readable, other than to enforce project-local style conventions. OP's example block of code is a classic example of how early-return can make code more readable. – tekHedd Mar 25 '20 at 17:57
0

Two things. First, you need to qualify the enum reference in your test - rather than "PLUS", it should be "Operator.PLUS". Second, this code would be a lot more readable if you used the enum member names rather than their integral values in the switch statement. I've updated your code:

public enum Operator
{
    PLUS, MINUS, MULTIPLY, DIVIDE
}

public static double Calculate(int left, int right, Operator op)
{
    switch (op)
    {
        default:
        case Operator.PLUS:
            return left + right;

        case Operator.MINUS:
            return left - right;

        case Operator.MULTIPLY:
            return left * right;

        case Operator.DIVIDE:
            return left / right;
    }
}

Call this with:

Console.WriteLine("The sum of 5 and 5 is " + Calculate(5, 5, Operator.PLUS));
Mike
  • 148
  • 1
  • 9
0

Your code is fine. In case you're not sure how to use Calculate function, try

Calculate(5,5,(Operator)0); //this will add 5,5
Calculate(5,5,Operator.PLUS);// alternate

Default enum values start from 0 and increase by one for following elements, until you assign different values. Also you can do :

public enum Operator{PLUS=21,MINUS=345,MULTIPLY=98,DIVIDE=100};
novic3
  • 106
  • 5