Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding the highest set flag in an enum value

Tags:

c#

.net

enums

I'm using a enum with flags attribute as a way of tracking status.

An example is the following:

Created = 1
Completed = 2
Dispatched = 4

Without writing anything too rigid (if check this, do that, if check that, do this) i want to be able to find the highest flag which has been set so in this example:

Item.Status = Status.Created | Status.Completed

the mythical method would return 2 - as completed is the flag set with the highest value.

GetMaxSetFlagValue(Item.Status) // returns 2

I've found questions which revolved around the actual enum, just not a value which uses flags. I'm fairly sure this could be achieved with Linq...?

like image 901
Phil Cooper Avatar asked Oct 16 '11 11:10

Phil Cooper


2 Answers

Something like the following should work:

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;
}

The method will fail if T is not an enum type, so a check should preferably be performed in the beginning of the method. Also it will not work for an enum with an underlying type larger than int (i.e. long).

like image 188
DeCaf Avatar answered Oct 18 '22 04:10

DeCaf


This is the extension method I use. It will give you the enum back

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

Output: maxStatus = Completed

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> ();
    }
}
like image 30
Derek Smalls Avatar answered Oct 18 '22 04:10

Derek Smalls