C # як використовувати enum з перемикачем


79

Я не можу зрозуміти, як використовувати перемикачі в поєднанні з переліком. Не могли б ви сказати мені, що я роблю не так, і як це виправити? Я повинен використовувати перерахування, щоб скласти основний калькулятор.

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;
        }
    }
}

Кінцевий результат повинен бути приблизно таким:

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

Не могли б ви, хлопці, сказати мені, як я зіпсуюсь?

Відповіді:


119

Не потрібно його перетворювати

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

До речі, використовуйте дужки


10
@ J.Starkl Ну, це питання думки, я думаю :-)
Stephan Bauer

@StephanBauer: Так, це :-)
J.Starkl

Я, скоріше, відступник, сам =) Як не дивно, це єдине, на що я не надягаю брекети. Піди розберися!
Кеннет К.

27
Якщо ви коли-небудь ввели нову змінну для використання в одному випадку, вам, звичайно, потрібно використовувати дужки. І в цей момент починається мій OCD, і мені потрібно зробити так, щоб усі справи виглядали однаково, додаючи до них дужки. (Якщо говорити серйозно, я використовую дужки в операторах перемикачів, тому що використовую їх для блоків скрізь.)
Метью Уотсон,

9
Так, але якщо ви їх використовуєте скрізь -немає підводних каменів -послідовний код -поліпшено читабельність -просте обслуговування / розширення -найкраща практика (звикайте до них)
J.Starkl

12

Оскільки C # 8.0 представив новий вираз перемикача для перелічень, ви можете зробити це ще елегантніше:

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
        }

Посилання https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8


10

Правильна відповідь уже дана, проте ось кращий спосіб (ніж перемикач):

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;
}

3
Я думаю, що це приклад того, де використання var для оголошення змінної було б доречним!
Chris Dunaway

1
Var не можна використовувати поза тілом методу.
JustAndrei

2
1. Розділення конфігурації та логіки: ваш код стає коротким і зручним для читання. Ваша конфігурація читається як таблиця, що також легко. 2. На відміну від switch, словник внутрішньо використовує хеш-таблицю для швидкого пошуку, що стає важливим, коли є багато випадків. Іноді програмісти ставлять найбільш використовуваний елемент в кінці комутатора і мають проблеми з продуктивністю. 3. Після того, як конфігурація витягнута з коду, тепер ви можете зробити багато чудових речей:
JustAndrei

1
A. Перемістіть його з коду у зовнішнє джерело, наприклад, файл конфігурації або базу даних. B. Динамічно змінюйте конфігурацію відповідно до ваших потреб, прямо під час виконання програми. C. Створіть систему плагінів, щоб ваша конфігурація була розширена модулями. D. Хоча словник вже допомагає швидше шукати ключ, ви можете зробити його ще кращим, налаштувавши спосіб пошуку операції. Одного разу я здійснив таку заміну комутатора, який накопичував статистику використання справ під час виконання програми, і періодично переупорядковував список справ таким чином, щоб найпопулярніший став першим.
JustAndrei

1
Я хотів би бачити один надійний доказ того, що пошук словника відбувається швидше, ніж "Переключення з переліченнями".
BillW


3

Ви не повинні перетворювати на ціле число. І для ділення, вам потрібно кинути ліворуч, щоб спочатку подвоїти, якщо ні, то ви будете робити ціле ділення.

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;
}

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);
            }
        }
    }

1

Якщо ви не хочете використовувати оператор return для кожного випадку, спробуйте наступне:

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

   return result;
}

Незрозуміло, як це робить код більш читабельним, за винятком того, щоб застосовувати конвенції стилю локального проекту. Приклад блоку коду OP - це класичний приклад того, як раннє повернення може зробити код більш читабельним.
tekHedd

1

Усі інші відповіді правильні, але вам також потрібно правильно назвати свій метод:

Calculate(5, 5, Operator.PLUS))

А оскільки ви використовуєте intдля leftі right, результат буде intтакож ( 3/2 will result in 1). ви можете виконати привід до doubleобчислення результату або змінити параметри, щоб прийнятиdouble


Ну .. так, начебто ... :-D
Стефан Бауер

1

Не потрібно конвертувати. Ви можете застосувати умови до Enums всередині комутатора. Як так,

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; 
    }
}

Тоді назвіть це так:

Console.WriteLine("The sum of 5 and 5 is " + Calculate(5, 5, Operator.PLUS));

Ця відповідь прекрасно ілюструє правильний час для порушення домовленості та використання 1) дострокового повернення з функції та 2) розміщення регістру в одному рядку з кодом.
tekHedd

0

Дві речі. По-перше, вам потрібно визначити посилання на перелік у вашому тесті - а не "PLUS", це має бути "Operator.PLUS". По-друге, цей код був би набагато зручнішим для читання, якби ви використовували імена членів перерахування, а не їхні інтегральні значення в операторі switch. Я оновив ваш код:

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;
    }
}

Зателефонуйте за цим номером:

Console.WriteLine("The sum of 5 and 5 is " + Calculate(5, 5, Operator.PLUS));

0

Ваш код чудовий. Якщо ви не впевнені, як використовувати функцію «Обчислити», спробуйте

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

Значення перерахування за замовчуванням починаються з 0 і збільшуються на одиницю для наступних елементів, поки ви не призначите різні значення. Також ви можете зробити:

public enum Operator{PLUS=21,MINUS=345,MULTIPLY=98,DIVIDE=100};
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.