Если у меня есть переменная, содержащая перечисление флагов, могу ли я как-то перебрать битовые значения в этой конкретной переменной? Или мне нужно использовать Enum.GetValues для перебора всего перечисления и проверки того, какие из них установлены?
c#
enums
enum-flags
Оливье Рожье
источник
источник
Ответы:
источник
HasFlag
это доступно начиная с .NET 4.Enum.GetValues(input.GetType()).Cast<Enum>().Where(input.HasFlag);
Тогда просто:myEnum.GetFLags()
:)static IEnumerable<Enum> GetFlags(this Enum input)
Вот решение проблемы Linq.
источник
.Where(v => !Equals((int)(object)v, 0) && e.HasFlag(v));
если у вас есть нулевое значение для представленияNone
Насколько я знаю, нет никаких встроенных методов для получения каждого компонента. Но вот один из способов получить их:
Я адаптировал то, что
Enum
работает внутри, для генерации строки, чтобы вместо этого возвращать флаги. Вы можете посмотреть код в отражателе, и он должен быть более или менее эквивалентным. Хорошо работает для общих случаев использования, когда есть значения, содержащие несколько битов.Метод расширения
GetIndividualFlags()
получает все индивидуальные флаги для типа. Таким образом, значения, содержащие несколько битов, не учитываются.источник
Bar
,Baz
аBoo
не простоBoo
.Boo
(значение, возвращаемое с помощьюToString()
). Я настроил его, чтобы разрешить только отдельные флаги. Итак, в моем примере вы можете получитьBar
иBaz
вместоBoo
.Возвращаясь к этому несколько лет спустя, с немного большим опытом, мой окончательный ответ только для однобитовых значений, переходя от младшего бита к старшему, - это небольшой вариант внутренней процедуры Джеффа Меркадо:
Кажется, это работает, и, несмотря на мои возражения, высказанные несколько лет назад, я использую здесь HasFlag, поскольку он гораздо более разборчив, чем использование побитовых сравнений, а разница в скорости незначительна для всего, что я буду делать. (Вполне возможно, что с тех пор они улучшили скорость HasFlags, насколько я знаю ... Я не тестировал.)
источник
yield return bits;
?Уходя от метода @Greg, но добавляя новую функцию из C # 7.3,
Enum
ограничение:Новое ограничение позволяет использовать этот метод расширения без необходимости передавать его
(int)(object)e
, и я могу использоватьHasFlag
метод и преобразовывать его напрямую вT
fromvalue
.В C # 7.3 также добавлены ограничения для delagates и
unmanaged
.источник
flags
параметрT
тоже был универсального типа , иначе вам пришлось бы явно указывать тип перечисления каждый раз, когда вы его вызываете.+1 за ответ @ RobinHood70. Я обнаружил, что мне удобна общая версия метода.
EDIT А + 1 для @AustinWBryan для приведения в C # 7.3 в пространстве решений.
источник
Вам не нужно перебирать все значения. просто проверьте свои конкретные флаги следующим образом:
или (как сказал pstrjds в комментариях) вы можете проверить его использование, например:
источник
Что я сделал, так это изменил свой подход, вместо того, чтобы вводить входной параметр метода в качестве
enum
типа, я ввел его как массивenum
типа (MyEnum[] myEnums
), таким образом я просто перебираю массив с помощью оператора switch внутри цикла.источник
Не был удовлетворен приведенными выше ответами, хотя они были началом.
После объединения нескольких различных источников здесь:
Предыдущий постер в этой теме
Флаги перечисления проекта кода QnA SO Проверить сообщение
Утилита Great Enum <T>
Я создал это, так что дайте мне знать, что вы думаете.
Параметры::
bool checkZero
указывает разрешить0
как значение флага. По умолчаниюinput = 0
возвращает пустое значение.bool checkFlags
: указывает ему проверить,Enum
украшен ли[Flags]
атрибут атрибутом.PS. У меня сейчас нет времени выяснять
checkCombinators = false
алгоритм, который заставит его игнорировать любые значения перечисления, которые являются комбинациями битов.При этом используется вспомогательный класс Enum <T> здесь , что я обновил к использованию
yield return
дляGetValues
:Наконец, вот пример его использования:
источник
Основываясь на ответе Грега выше, это также учитывает случай, когда у вас есть значение 0 в вашем перечислении, например None = 0. В этом случае он не должен повторять это значение.
Кто-нибудь знает, как улучшить это еще больше, чтобы он мог обрабатывать случай, когда все флаги в перечислении установлены супер-умным способом, который может обрабатывать все базовые типы перечисления и случай All = ~ 0 и All = EnumValue1 | EnumValue2 | EnumValue3 | ...
источник
Вы можете использовать итератор из Enum. Начиная с кода MSDN:
Это не проверено, поэтому, если я допустил ошибку, смело звоните мне. (очевидно, что это не реентерабельность.) Вам придется назначить значение заранее или разбить его на другую функцию, которая использует enum.dayflag и enum.days. Вы могли бы пойти куда-нибудь с контуром.
источник
Это может быть также следующий код:
Он идет внутрь, если только значение перечисления содержится в значении
источник
Все ответы хорошо работают с простыми флагами, вы, вероятно, столкнетесь с проблемами при объединении флагов.
вероятно, потребуется добавить проверку, чтобы проверить, является ли само значение перечисления комбинацией. Вам, вероятно, понадобится что-то вроде написанного здесь Хенком ван Бойеном, чтобы удовлетворить ваши требования (вам нужно немного прокрутить вниз)
источник
Метод расширения с использованием нового ограничения Enum и дженериков для предотвращения приведения типов:
источник
Вы можете сделать это напрямую, преобразовав в int, но потеряете проверку типов. Я думаю, что лучше всего использовать что-то похожее на мое предложение. Он всегда сохраняет правильный тип. Конверсия не требуется. Он не идеален из-за бокса, который немного прибавит производительности.
Не идеально (бокс), но выполняет свою работу без предупреждения ...
Использование:
источник