Проверьте, содержит ли перечисление более одного флага - PullRequest
4 голосов
/ 29 февраля 2020

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

[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

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

Ответы [ 4 ]

2 голосов
/ 01 марта 2020

Если вы используете. NET Core 3.0+, вы можете использовать PopCount , он возвращает количество бит "1" в uint или ulong и использует POPCNT Инструкция CPU (если CPU поддерживает SSE4, в противном случае он будет использовать программный резерв).

public static bool MoreThanOneFlag(Foo foo)
{
    return BitOperations.PopCount((uint)foo) > 1;
}
Foo one = Foo.Bar;
Foo two = Foo.Bar | Foo.Far;

Console.WriteLine(MoreThanOneFlag(one)); //false
Console.WriteLine(MoreThanOneFlag(two)); //true
1 голос
/ 02 марта 2020

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

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

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

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

 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# ссылка)

1 голос
/ 29 февраля 2020

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

В следующем примере определяется am Helper метода расширения, который возвращает 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'
}
0 голосов
/ 01 марта 2020

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

[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 против побитовой проверки и проверки оператора

...