Decoding a bitmask from a value in C#
Asked Answered
B

2

6

I am trying to decode a bitmask

[Flags]
public enum Amenities
{
    BusinessCenter = 1,
    FitnessCenter = 2,
    HotTub = 4,
    InternetAccess = 8,
    KidsActivities = 16,
    Kitchen = 32,
    PetsAllowed = 64,
    Pool = 128,
    Restaurant = 256,
    Spa = 512,
    Whirlpool = 1024,
    Breakfast = 2048,
    Babysitting = 4096,
    Jacuzzi = 8192,
    Parking = 16384,
    RoomService = 32768,
    AccessibleTravel = 65536,
    AccessibleBathroom = 131072,
    RollShower = 262144,
    HandicappedParking = 524288,
    InRoomAccessibility = 1048576,
    AccessibilityDeaf = 2097152,
    BrailleSignage = 4194304,
    FreeAirportShuttle = 8388608,
    IndoorPool =  16777216,
    OutdoorPool = 33554432,
    ExtendedParking = 67108864,
    FreeParking = 134217728
}

How do I write a function that decodes a value like 5722635 and returns a list of all Amenities that are encoded in 5722635.

the result should look like this:

This Property has the following Amenities:

  • Business Center
  • Fitness Center
  • Internet Access
  • Available Spa On-site
  • Babysitting
  • Parking
  • Accessible Path of Travel
  • Accessible Bathroom
  • Roll-in Shower
  • In-room Accessibility
  • Braille or Raised Signage

I have been trying things like

public List<Amenities> Decode(long mask)
        {
            var list = new List<Amenities>();
            for (var index = 0; index < 16; index++)
            {
                var bit = 1 << index;
                if (0 != (bit & mask))
                {
                    list.Add(new Amenities(index));
                }
            }
            return list;
        }

But can not get it to work. Any suggestions on how to make this work properly would be appreciated.

Butyraldehyde answered 4/12, 2014 at 12:58 Comment(2)
16 isn't enough and that new syntax to cast probably doesn't workColum
the new syntax definitely does not work. You cannot create a 'new' instance of an enum member like thatHeterolysis
S
13

What about one-liner?

var mask = (Amenities)5722635;

var result =
    Enum.GetValues(typeof(Amenities))
        .Cast<Amenities>()
        .Where(value => mask.HasFlag(value))
        .ToList();

You can cache result of Enum.GetValues(typeof(Amenities)).Cast<Amenities>() in order to improve performance.

Spireme answered 4/12, 2014 at 13:4 Comment(1)
This simple solution did get the job done... thanx pwasButyraldehyde
R
3

Firstly, your method is taking in a long, yet your enum implicitly uses an int as the underlying data type. Either store the value as an int or change the underlying data type in your enum to a long: [Flags] public enum Amenities : long { ... }

Secondly, if your enum is marked with the FlagsAttribute you really don't need to turn the value into an list of values, you can use the Enum.HasFlag() method to check for a flagged value. You'll have to cast your long into an Amenities type first:

var amenities = (Amenities)mask;

if (amentities.HasFlag(Amenities.BusinessCenter)) { ... }

But, if you really want to split that flag into a list of amenities instead:

public IList<Amenities> Decode(long mask)
{
        var amenities = (Amenities)mask;
        var list = new List<Amenities>();

        foreach (Amenities amenity in Enum.GetValues(typeof(Amenities))
        {
            if (amenities.HasFlag(amenity))
                list.Add(amenity);
        }

        return list;
}
Rabies answered 4/12, 2014 at 13:9 Comment(1)
This also works very well and follows the initial idea I was after. Thank you m-yButyraldehyde

© 2022 - 2024 — McMap. All rights reserved.