Проверить, содержит ли перечисление более одного флага

Я пытаюсь проверить, содержит ли «экземпляр перечисления» более одного флага.

[Flags]
public enum Foo 
{
  Bar = 1,
  Far = 2
}
var multiState = Foo.Bar | Foo.Far;

MoreThanOneFlag(multiState); // True

var singleState = Foo.Bar;

MoreThanOneFlag(singleState); // False

Кроме того, я действительно не хочу использовать что-то вроде следующего:

var state = Foo.Bar | Foo.Far;

Console.WriteLine(state.ToString().Count(x => x == ',') > 0); // True

Заметьте, меня не волнует, какие флаги содержит «экземпляр», я просто хочу знать, их больше одного.


person Twenty    schedule 29.02.2020    source источник
comment
Так могут быть дубликаты, например this Вы можете использовать оператор и & или HasFlag метод   -  person Pavel Anikhouski    schedule 29.02.2020
comment
@PavelAnikhouski Я уже смотрел на них, я просто хочу знать, ли установлено более одного флага. Эти ответы проверяют, установлен ли конкретный флаг.   -  person Twenty    schedule 29.02.2020
comment
Выполните битовую операцию ... bool value = (multiState & (multiState -1)) != 0;   -  person zaggler    schedule 29.02.2020
comment
@ Öđěxěŕ Это было именно то, что я искал. К сожалению, я только что заметил, что мог искать набор битов, облом.   -  person Twenty    schedule 29.02.2020
comment
У вас всего два флага? (и, следовательно, только одна комбинация из нескольких флагов) или вы ищете общее решение этой проблемы   -  person Steve    schedule 29.02.2020
comment
@Steve Это простой пример, он должен работать для любого количества флагов.   -  person Twenty    schedule 29.02.2020
comment
Отвечает ли это на ваш вопрос? Подсчет количества флагов, установленных в перечислении   -  person Pavel Anikhouski    schedule 29.02.2020
comment
@PavelAnikhouski Я не особо хотел это считать, решения разнятся, пусть даже немного.   -  person Twenty    schedule 29.02.2020
comment
Почему вы хотите знать, является ли ваша ценность комбинацией? Обычно вы просто хотите получить включенные биты.   -  person HimBromBeere    schedule 29.02.2020
comment
Может быть, они хотят проверить недопустимые комбинации   -  person Chronicle    schedule 29.02.2020
comment
@ Öđěxěŕ Это должен быть ответ, а не комментарий.   -  person Alsein    schedule 29.02.2020
comment
@Liam да, но на самом деле нет. Под этим постом гораздо больше ответов, которые, по моему мнению, лучше подходят, по крайней мере, для меня. Кроме того, некоторые из них даже быстрее.   -  person Twenty    schedule 04.12.2020
comment
Что ж, эти ответы должны быть добавлены к более старому (-ым) вопросу (-ам). Это должно было быть закрыто как обман 9 месяцев назад, так как вопрос уже задавался несколько раз. Фактически, это очевидная цель обмана для обоих, Как проверить, установлено ли несколько флагов перечисления?   -  person Liam    schedule 04.12.2020


Ответы (3)


Я пытаюсь проверить, содержит ли «экземпляр перечисления» более одного флага. Меня не волнует, какие флаги содержит "экземпляр", я просто хочу знать, есть ли более одного

Кроме того, я действительно не хочу использовать что-то вроде следующего:

 var state = Foo.Bar | Foo.Far;
 Console.WriteLine(state.ToString().Count(x => x == ',') > 0); // True

Есть несколько разных способов добиться того, чего вы хотите, я предлагаю провести немного (побитовую) проверку:

 public static bool MoreThanOneFlag<TValue>(TValue flag) where TValue : Enum => (Convert.ToInt32(flag) & (Convert.ToInt32(flag) - 1)) != 0;

В приведенном выше блоке кода мы проверяем, не является ли flag степенью двойки, проверяя с помощью flag & (flag-1)) != 0 (оператор &), который вычисляет поразрядное логическое И для своих операндов. Если установлен только один флаг, мы предполагаем, что значение будет степенью двойки, в противном случае это не степень двойки.

Или, если вам не нужна вспомогательная функция, просто выполните эту проверку где угодно:

 bool value = (multiState & (multiState -1)) != 0;

Для получения дополнительной информации о побитовом, узнайте больше здесь.

Использованная литература :

Побитовые операторы и операторы сдвига (C # ссылка)

person zaggler    schedule 02.03.2020
comment
Я люблю это! Однако вам не нужно использовать Convert.ToInt32. Просто приведение к int отлично работает. Если вы ДЕЙСТВИТЕЛЬНО завершены, вы должны проверить интегральный тип и использовать его для значений. Однако это выходит за рамки этого. :-) - person Jamie; 23.06.2021

Вы можете использовать функцию двоичного логарифма для значения enum, а затем проверить, является ли результат целым числом.

В следующем примере определяется вспомогательный метод Extension Method, который возвращает true, если установлено несколько флагов:

HelperExtenxsions.cs

public static class HelperExtenxsions
{
  public static bool HasMultipleFlags(this IConvertible enumValue) 
  {
    return Math.Log(enumValue.ToInt32(CultureInfo.InvariantCulture.NumberFormat), 2) % 1 != 0;
  }
}

Foo.cs

[Flags]
public enum Foo 
{
  Bar = 1,
  Far = 2
}

Program.cs

public static void Main()
{ 
  var enumValue = Foo.Bar | Foo.Far; 
  Console.WriteLine(enumValue.HasMultipleFlags()); // Prints 'True'

  enumValue = Foo.Bar;
  Console.WriteLine(enumValue.HasMultipleFlags()); // Prints 'False'
}
person BionicCode    schedule 29.02.2020
comment
Enum - допустимое ограничение в современном C #. Вы можете сделать TEnum: Enum - person Chronicle; 29.02.2020
comment
Да исправить. Но я думаю, вы не можете просто преобразовать Enum в целочисленное значение с помощью приведения. - person BionicCode; 29.02.2020

Вы можете использовать Enum.GetValues в соединении с Enum.HasFlag(Enum), чтобы перебирать каждую константу и определять, установлены ли битовые поля в текущем экземпляре, и возвращать его счетчик.

[Flags]
public enum Foo
{
  One = 1,
  Two = 2,
  Four = 4,
  Eight = 8
}

var state1 = Foo.One;
var state2 = Foo.Two;//
var state3 = Foo.One | Foo.Two; 
var state4 = Foo.Two | Foo.Four;

Console.WriteLine(MoreThanOneFlag(state1));//false
Console.WriteLine(MoreThanOneFlag(state2));//false
Console.WriteLine(MoreThanOneFlag(state3));//true
Console.WriteLine(MoreThanOneFlag(state4));// true
private static bool MoreThanOneFlag<TEnum>(TEnum state) where TEnum : Enum
{
  var names = Enum.GetValues(typeof(TEnum));
  var Flagcounter = names.OfType<TEnum>().Where(x=>state.HasFlag((TEnum)x)).Count();
  return Flagcounter > 1 ? true : false;
}

Примечание. Хотя Enum.HasFlags может не подходить, если ваше приложение требует производительности, но оно надежное, чистое , и делает код очень наглядным и выразительным

Ссылка:

C # Enum.HasFlag против побитовой проверки оператора И

person Clint    schedule 29.02.2020