Як ви передаєте кілька значень перерахунків у C #?


117

Іноді під час читання інших кодів C # я бачу метод, який прийме декілька значень перерахунку в одному параметрі. Я завжди думав, що це якось акуратно, але ніколи не заглядав у це.

Ну, зараз я думаю, що у мене може виникнути потреба в цьому, але не знаю, як це зробити

  1. встановіть підпис методу, щоб прийняти це
  2. робота зі значеннями в методі
  3. визначити перерахунок

досягти такого роду.


У моїй конкретній ситуації я хотів би використовувати System.DayOfWeek, який визначається як:

[Serializable]
[ComVisible(true)]
public enum DayOfWeek
{ 
    Sunday = 0,   
    Monday = 1,   
    Tuesday = 2,   
    Wednesday = 3,   
    Thursday = 4,   
    Friday = 5,    
    Saturday = 6
}

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


1
Як було сказано нижче, ви можете використовувати переліки прапорів. Ви можете перевірити внески та переходи переліків на C # , що містить більше інформації про роботу з переліками прапорів.
— ChaseMedallion

Відповіді:


181

Коли ви визначаєте enum, просто віднесіть його до [Flags], встановіть значення на дві потужності, і він буде працювати таким чином.

Ніщо інше не змінюється, крім передачі декількох значень у функції.

Наприклад:

[Flags]
enum DaysOfWeek
{
   Sunday = 1,
   Monday = 2,
   Tuesday = 4,
   Wednesday = 8,
   Thursday = 16,
   Friday = 32,
   Saturday = 64
}

public void RunOnDays(DaysOfWeek days)
{
   bool isTuesdaySet = (days & DaysOfWeek.Tuesday) == DaysOfWeek.Tuesday;

   if (isTuesdaySet)
      //...
   // Do your work here..
}

public void CallMethodWithTuesdayAndThursday()
{
    this.RunOnDays(DaysOfWeek.Tuesday | DaysOfWeek.Thursday);
}

Детальніше дивіться в документації MSDN про типи перерахування .


Відредагуйте у відповідь на доповнення до запитання.

Ви не зможете використовувати цей перелік, як є, якщо ви не хочете зробити щось на зразок передавати його як масив / колекція / парами масив. Це дозволить вам передати кілька значень. Синтаксис прапорів вимагає, щоб Enum був вказаний як прапори (або для того, щоб бастардизувати мову таким чином, що його не розроблено).


9
Я думаю, що якщо ви хочете, щоб це спрацювало, значення потрібно визначити як потужність двох, по одному біту для кожного значення. Що відбувається, це те, що ви передаєте побітові АБО значення в параметрі, які ви можете перевірити, використовуючи побітові І операції. Якщо ви не подбаєте про визначення значень як, наприклад, 1,2,4,8 тощо, у вас виникнуть проблеми.
— Денис Троллер

1
Просто встановлення атрибута Flags не працює автоматично. Я просто спробував це.
— Річард Ентоні Хайн

1
Ти маєш рацію, і я зняв дезінформацію. Виправлено код і для нього.
— Меттью Шарлі

@monoxide: я одночасно виправив це рішення - вибачте, що ви змінили ваші зміни
— Рід Копсей

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

78

Я думаю, що більш елегантним рішенням є використання HasFlag ():

    [Flags]
    public enum DaysOfWeek
    {
        Sunday = 1,
        Monday = 2,
        Tuesday = 4,
        Wednesday = 8,
        Thursday = 16,
        Friday = 32,
        Saturday = 64
    }

    public void RunOnDays(DaysOfWeek days)
    {
        bool isTuesdaySet = days.HasFlag(DaysOfWeek.Tuesday);

        if (isTuesdaySet)
        {
            //...
        }
    }

    public void CallMethodWithTuesdayAndThursday()
    {
        RunOnDays(DaysOfWeek.Tuesday | DaysOfWeek.Thursday);
    }

Є ще одна важлива річ, яку потрібно знати, якщо ви робите це так: Це додає набагато більшої гнучкості, коли вам потрібно динамічно заповнювати свій перелік. Напр .: Якщо ви використовуєте прапорці для визначення днів, у які ви хочете запускати свою програму, і ви намагатиметесь виконати це так, як це зроблено вище, код буде нечитабельним. Тож замість цього ви можете це зробити так: ... DaysOfWeek days = new DaysOfWeek(); if (cbTuesday.Checked) days |= DaysOfWeek.Tuesday; if (cbWednesday.Checked) days |= DaysOfWeek.Wednesday;...
— CoastN

25

Я другий відповідь Рід. Однак, створюючи enum, ви повинні вказати значення для кожного члена enum, щоб він робив свого роду бітове поле. Наприклад:

[Flags]
public enum DaysOfWeek
{
    Sunday = 1,
    Monday = 2,
    Tuesday = 4,
    Wednesday = 8,
    Thursday = 16,
    Friday = 32,
    Saturday = 64,

    None = 0,
    All = Weekdays | Weekend,
    Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday,
    Weekend = Sunday | Saturday,
    // etc.
}

1
Це допоможе вам, якщо вам колись знадобиться перевірити значення DaysOfWeek, наприклад, якщо ви читаєте те, яке зберігається в базі даних. Крім того, він надає кращу документацію для інших програмістів, оскільки деякі перераховують дні тижня, починаючи з понеділка замість неділі.
— Яків

3
Для наочності та ремонтопридатності я б написав ваші перерахунки "Усі" як "Неділя | Понеділок | Вівторок | Середа | Четвер | П'ятниця | Субота" ... і використовував подібні позначення для "Будні" та "Вихідні дні".
— Роберт Картенто

Це добре, якщо ви хочете створити свій власний перелік, але, щоб відповісти на питання, ви не можете змінити існуючий перелік «DaysOfWeek»
— Роберт Полсон

2
Не "може захотіти" ... ТИ ПОВИНЕН. Побізне порівняння цього вимагає. Залишити значення не визначеними, не вийде.
— Річард Ентоні Хайн

11

У моїй конкретній ситуації я хотів би використовувати System.DayOfWeek

Ви не можете використовувати System.DayOfWeek як [Flags]перерахунок, оскільки ви не маєте над ним контролю. Якщо ви хочете мати метод, який приймає кілька, DayOfWeekвам доведеться використовувати paramsключове слово

void SetDays(params DayOfWeek[] daysToSet)
{
    if (daysToSet == null || !daysToSet.Any())
        throw new ArgumentNullException("daysToSet");

    foreach (DayOfWeek day in daysToSet)
    {
        // if( day == DayOfWeek.Monday ) etc ....
    }
}

SetDays( DayOfWeek.Monday, DayOfWeek.Sunday );

В іншому випадку ви можете створити власне [Flags]перерахування, як його окреслили численні інші респонденти, і використовувати побізні порівняння.


2
Я не знаю, чому я не думав про парами. Це має бути дуже корисно для використання переписувачів, які не є бітфілдами.
— Ронні Овербі

10
[Flags]
public enum DaysOfWeek
{
  Mon = 1,
  Tue = 2,
  Wed = 4,
  Thur = 8,
  Fri = 16,
  Sat = 32,
  Sun = 64
}

Ви повинні вказати числа та наростити їх таким чином, оскільки це зберігає значення побіжно.

Тоді просто визначте свій метод, щоб взяти цей перелік

public void DoSomething(DaysOfWeek day)
{
  ...
}

і закликати це робити щось на кшталт

DoSomething(DaysOfWeek.Mon | DaysOfWeek.Tue) // Both Monday and Tuesday

Щоб перевірити, чи було включено одне із значень перерахування, перевірте їх, використовуючи побітові операції, як-от

public void DoSomething(DaysOfWeek day)
{
  if ((day & DaysOfWeek.Mon) == DaysOfWeek.Mon) // Does a bitwise and then compares it to Mondays enum value
  {
    // Monday was passed in
  }
}

Не відповідає на запитання. "У моїй конкретній ситуації я хотів би використовувати System.DayOfWeek"
— Роберт Полсон

Але це саме те, що я шукав. Тож дякую все одно.
— Тілліто

3
[Flags]
    public enum DaysOfWeek{


        Sunday = 1 << 0,
        Monday = 1 << 1,
        Tuesday = 1 << 2,
        Wednesday = 1 << 3,
        Thursday = 1 << 4,
        Friday =  1 << 5,
        Saturday =  1 << 6
    }

викликати метод у такому форматі

MethodName (DaysOfWeek.Tuesday | DaysOfWeek.Th Thursday);

Реалізуйте метод EnumToArray, щоб пройти параметри

private static void AddEntryToList(DaysOfWeek days, DaysOfWeek match, List<string> dayList, string entryText) {
            if ((days& match) != 0) {
                dayList.Add(entryText);
            }
        }

        internal static string[] EnumToArray(DaysOfWeek days) {
            List<string> verbList = new List<string>();

            AddEntryToList(days, HttpVerbs.Sunday, dayList, "Sunday");
            AddEntryToList(days, HttpVerbs.Monday , dayList, "Monday ");
            ...

            return dayList.ToArray();
        }

Не відповідає на запитання. "У моїй конкретній ситуації я хотів би скористатися System.DayOfWeek"
— Роберт Полсон

Дякую, Роберто, але тобі не потрібно вказувати це на кожній відповіді.
— Ронні Овербі

@Ronnie - Навряд чи я винен, що існує стільки відповідей, що майже повторюються, що насправді не відповіли на питання.
— Роберт Поулсон

@Rony - перерахунки ToString () та Enum.Parse () будуть правильно виводити / аналізувати перерахування [Прапорів] (доки ви обережно ставитеся до версії перерахунку)
— Роберт Полсон,

@Robert - Я не думаю, що ніхто тебе звинувачує. Просто нехай голоси ведуть розмови.
— Ронні Овербі

3

Позначте перерахунок за допомогою атрибута [Прапори]. Також переконайтесь, що всі ваші значення взаємовиключні (два значення не можуть дорівнювати іншим), як у вашому випадку 1,2,4,8,16,32,64

[Flags]
public enum DayOfWeek
{ 
Sunday = 1,   
Monday = 2,   
Tuesday = 4,   
Wednesday = 8,   
Thursday = 16,   
Friday = 32,    
Saturday = 64
}

Коли у вас є метод, який приймає перерахунок DayOfWeek, використовуйте побітовий або оператор (|) для використання кількох членів разом. Наприклад:

MyMethod(DayOfWeek.Sunday|DayOfWeek.Tuesday|DayOfWeek.Friday)

Щоб перевірити, чи містить параметр конкретний член, використовуйте порозрядне значення та оператор (&) з тим членом, для якого ви перевіряєте.

if(arg & DayOfWeek.Sunday == DayOfWeek.Sunday)
Console.WriteLine("Contains Sunday");

Не відповідає на запитання. "У моїй конкретній ситуації я хотів би використовувати System.DayOfWeek"
— Роберт Полсон

2

Рід Копсі є правильним, і я би додавав його до оригінальної публікації, якщо зможу, але не можу, тому мені доведеться відповісти замість цього.

Небезпечно просто використовувати [Прапори] на будь-якому старому переліку. Я вважаю, що вам потрібно чітко змінити значення перерахунків на потужність двох при використанні прапорів, щоб уникнути зіткнення значень. Дивіться вказівки щодо FlagsAttribute та Enum .



-3

Щось такого характеру повинно показувати, що ви шукаєте:

[Flags]
public enum SomeName
{
    Name1,
    Name2
}

public class SomeClass()
{
    public void SomeMethod(SomeName enumInput)
    {
        ...
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.