1

We have an application that secures api controller actions via a bit mask. What I am trying to do is get the list of enums based on the bit mask value.

Here is an example Enum:

    [Flags]
    public enum DriverChange : long
    {
        CanAccess = 1 << 0,
        CanView = 1 << 1,
        CanUpdate = 1 << 2,
        MayPerformBaseFunctions = 1 << 3,
        CanAddPool = 1 << 4,
        CanModifyPool = 1 << 5,

    }

We create a permission by adding the bits and storing the integer value. Like this:

public class DriverDataChange
    {
        public const int None = 0;
        public const int View = (int)(Permissions.DriverDataChange.CanAccess |
                                                Permissions.DriverDataChange.CanView |
                                                Permissions.DriverDataChange.MayPerformBaseFunctions);
        public const int MassUpload = (int)(Permissions.DriverDataChange.CanAccess |
                                                Permissions.DriverDataChange.CanView |
                                                Permissions.DriverDataChange.CanUpdate |
                                                Permissions.DriverDataChange.MayPerformBaseFunctions |
                                                Permissions.DriverDataChange.CanPerformMassUpload);
        public const int FullNoMassUpload = (int)(Permissions.DriverDataChange.CanAccess |
                                                Permissions.DriverDataChange.CanView |
                                                Permissions.DriverDataChange.CanUpdate |
                                                Permissions.DriverDataChange.MayPerformBaseFunctions |
                                                Permissions.DriverDataChange.CanAddPool |
                                                Permissions.DriverDataChange.CanModifyPool |
                                                Permissions.DriverDataChange.CanAddDriver |
                                                Permissions.DriverDataChange.CanModifyDriver |
                                                Permissions.DriverDataChange.CanUnassignVehicle |
                                                Permissions.DriverDataChange.CanCloneVehicleDetails |
                                                Permissions.DriverDataChange.CanModifyVehicleClientDataFields);
        public const int Full = (int)(Permissions.DriverDataChange.CanAccess |
                                                Permissions.DriverDataChange.CanView |
                                                Permissions.DriverDataChange.CanUpdate |
                                                Permissions.DriverDataChange.MayPerformBaseFunctions |
                                                Permissions.DriverDataChange.CanAddPool |
                                                Permissions.DriverDataChange.CanModifyPool |
                                                Permissions.DriverDataChange.CanAddDriver |
                                                Permissions.DriverDataChange.CanModifyDriver |
                                                Permissions.DriverDataChange.CanUnassignVehicle |
                                                Permissions.DriverDataChange.CanCloneVehicleDetails |
                                                Permissions.DriverDataChange.CanModifyVehicleClientDataFields |
                                                Permissions.DriverDataChange.CanPerformMassUpload);
    }

what I would like to do is get the list of <T> values based on the integer value.

I found this, but it will not work with bit shift values:

List<Permissions.DriverDataChange> permissionDetails =Enum.GetValues(typeof(Permissions.DriverDataChange))
                                                .Cast<Enum>()
                                                .Where(m => DriverDataChange.Full.HasFlag(m))
                                                .Cast<Permissions.DriverDataChange>();
Community
  • 1
  • 1
JDBennett
  • 1,323
  • 17
  • 45

2 Answers2

2

Your problem is that you have defined the data in DriverDataChange as int rather than as DriverChange.

Instead define them like this:

public const DriverDataChange View = (DriverDataChange.CanAccess |
                                         DriverDataChange.CanView |
                                         DriverDataChange.MayPerformBaseFunctions);

And then you can query them:

var permissionDetails = Enum.GetValues(typeof(DriverDataChange)).Cast<DriverDataChange>()
                             .Where(m => DriverDataChangeData.View.HasFlag(m));

Which returns:

CanAccess
CanView
MayPerformBaseFunctions

Edit:

If you have to keep the values of DriverDataChange as int, then you can cast them in the check:

var permissionDetails = Enum.GetValues(typeof(DriverDataChange)).Cast<DriverDataChange>()
                   .Where(m => ((DriverDataChange)DriverDataChangeData.View).HasFlag(m));
stuartd
  • 70,509
  • 14
  • 132
  • 163
  • I can't change that. That is existing code. It is defined as an int because it represents the binary sum of the assigned values. – JDBennett Nov 16 '16 at 22:20
  • ?? You could just cast them. Anyway, sounds like you will eventually end out having to change it, as the underlying enum is a `long` and your int values won't be big enough to contain them. – stuartd Nov 17 '16 at 10:25
0

Here is how I did it

var permissionDetails = 
            Enum.GetValues(typeof(DriverDataChange))
           .Cast<int>()
           .Where(m => (DriverDataChangeData.View & m) > 0)
           .Cast<DriverDataChange>();

I also wrote an extension

    public static class EnumExtensions
    {
        public static IEnumerable<T> UnfoldBitmask<T>(int bitMask)
        {
            return Enum.GetValues(typeof(T)).Cast<int>().Where(m => (bitMask & m) > 0).Cast<T>();
        }
    }

Here is how you would call it

int permissionDetails = EnumExtensions.UnfoldBitmask<DriverDataChange>(DriverDataChangeData.View );
Murometz80
  • 21
  • 4