Нахождение самого высокого установленного флага в значении перечисления - PullRequest
8 голосов
/ 16 октября 2011

Я использую перечисление с атрибутом flags для отслеживания статуса.

Примером является следующее:

Created = 1
Completed = 2
Dispatched = 4

Без написания чего-либо слишком жесткого (если проверить это, сделать это, если проверить это, сделать это), я хочу быть в состоянии найти самый высокий флаг, который был установлен так в этом примере:

Item.Status = Status.Created | Status.Completed

мифический метод вернет 2 - завершен флаг, установленный с самым высоким значением.

GetMaxSetFlagValue(Item.Status) // returns 2

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

Ответы [ 3 ]

8 голосов
/ 16 октября 2011

Должно сработать что-то вроде следующего:

static int GetMaxSetFlagValue<T>(T flags) where T : struct
{
   int value = (int)Convert.ChangeType(flags, typeof(int));
   IEnumerable<int> setValues = Enum.GetValues(flags.GetType()).Cast<int>().Where(f => (f & value) == f);
   return setValues.Any() ? setValues.Max() : 0;
}

Метод завершится ошибкой, если T не является типом enum, поэтому предпочтительно выполнить проверку в начале метода.Также это не будет работать для перечисления с базовым типом, большим чем int (то есть long).

2 голосов
/ 29 февраля 2012

Это метод расширения, который я использую. Это вернет вам перечисление

var maxStatus = Item.Status.GetFlags().Max();

Вывод: maxStatus = Завершено

public static class EnumExtensions {

    /// <summary>Enumerates get flags in this collection.</summary>
    ///
    /// <param name="value">The value.
    /// </param>
    ///
    /// <returns>An enumerator that allows foreach to be used to process get flags in this collection.</returns>
    public static IEnumerable<T> GetFlags<T> (this T value) where T : struct {
        return GetFlags (value, Enum.GetValues (value.GetType ()).Cast<T> ().ToArray ());
    }

    /// <summary>Enumerates get flags in this collection.</summary>
    ///
    /// <param name="value"> The value.
    /// </param>
    /// <param name="values">The values.
    /// </param>
    ///
    /// <returns>An enumerator that allows foreach to be used to process get flags in this collection.</returns>
    private static IEnumerable<T> GetFlags<T> (T value, T [] values) where T : struct {
        if (!typeof (T).IsEnum) {
            throw new ArgumentException ("Type must be an enum.");
        }
        ulong bits = Convert.ToUInt64 (value);
        var results = new List<T> ();
        for (int i = values.Length - 1; i >= 0; i--) {
            ulong mask = Convert.ToUInt64 (values [i]);
            if (i == 0 && mask == 0L)
                break;
            if ((bits & mask) == mask) {
                results.Add (values [i]);
                bits -= mask;
            }
        }
        if (bits != 0L)
            return Enumerable.Empty<T> ();
        if (Convert.ToUInt64 (value) != 0L)
            return results.Reverse<T> ();
        if (bits == Convert.ToUInt64 (value) && values.Length > 0 && Convert.ToUInt64 (values [0]) == 0L)
            return values.Take (1);
        return Enumerable.Empty<T> ();
    }
}
1 голос
/ 07 июня 2016

Поскольку вы можете разыгрывать взад-вперед на уинт, вы можете использовать:

public uint LowestBit(uint x) 
{
    return ~(x&x-1)&x;
}
public uint HighestBit(uint x)
{
    uint last = x;
    while (x!=0) 
    {
        last=x;
        x&=x-1;
    }
    return last;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...