C# how to use enum with switch
Asked Answered
I

11

115

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?

Intracutaneous answered 28/2, 2013 at 12:56 Comment(0)
L
173

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

Lovelorn answered 28/2, 2013 at 12:58 Comment(11)
@Lovelorn Well that's a matter of opinion, I think :-)Patois
@StephanBauer: Yes, it is :-)Lovelorn
More of an indent man, myself =) Strangely enough, that's the only thing I don't put braces on. Go figure!Merchandise
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.)Bulbous
@MatthewWatson Great! Thanks for mentioning that point with variabloes for a single case - never thought of that :-)Patois
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: #174655Frizzle
Yes, but if you use them everywhere -no pitfalls -consistent code -improved readability -simpler maintenence/extension -best practice (get used to them)Lovelorn
about the readability - I find python and haskell code way easier to read than c# or javaConfessedly
Note that the brackets isn't related to the switch/case: You can add brackets anywhere you want to separate variables.Ardatharde
Switch case enables you to reuse the same code block for multiple cases. If you do - make sure to not use brackets.Patti
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.Bran
G
36

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 => (double)left / right,
                _ => 0
            }

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

Gonadotropin answered 9/10, 2019 at 5:53 Comment(2)
Any syntactic sugar which reduces the need for curly braces is good.Bunsen
Please cast one of the divided values into a double, don't confuse newcomers and spread incorrect code.Wyant
M
11

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;
}
Mask answered 28/2, 2013 at 13:7 Comment(10)
I think this is an example of where using var to declare the variable would be appropriate!Mcelrath
Var cannot be used outside the method body.Mask
Oh yes, I missed that it was declared outside of the method.Mcelrath
You can use using OperatorsDict = Dictionary<Operator, Func<int, int, double>> and then use OperatorsDict insteadScala
@Mask - (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.Bewhiskered
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:Mask
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.Mask
I'd like to see one reliable piece of evidence that Dictionary look-up is faster than 'Switch with Enums.Trinomial
@Trinomial You won't, because it isn't. Using a dictionary for this is a simply dreadful design choice.Bunsen
According to this answer, compiler optimizations will automatically select switch or dictionary implementations based on the number of values being processed. Thus, you should use the syntax you prefer and let the compiler figure out the rest. I think most would prefer switch syntax. This answer is not unequivocally "better".Stackhouse
C
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;
}
Chignon answered 28/2, 2013 at 12:59 Comment(0)
D
3

simply don't cast to int

 switch(operator)
    {
       case Operator.Plus:
       //todo
Decencies answered 28/2, 2013 at 12:59 Comment(0)
N
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));
Nkrumah answered 11/1, 2017 at 4:38 Comment(1)
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.Bran
R
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);
            }
        }
    }
Richia answered 28/2, 2013 at 13:2 Comment(0)
P
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

Patois answered 28/2, 2013 at 13:2 Comment(1)
Well .. yes, kind of... :-DPatois
D
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;
}
Dutiful answered 3/10, 2014 at 9:27 Comment(1)
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.Bran
E
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));
Egidio answered 28/2, 2013 at 13:3 Comment(0)
P
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};
Pupa answered 28/2, 2013 at 13:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.