0

Is possible list a flag based in combination.

Using ProfileTypeFlag.SupplierMaster get a list just of "Supplier | Master | External"

I'm trying use this code. But they return all enums;

    public List<string> SetRoles(ProfileTypeFlag role)
        {
            List<string> result = new List<string>();
            foreach (ProfileTypeFlag r in Enum.GetValues(typeof(ProfileTypeFlag)))
            {
                if ((role & r) != 0) result.Add(r.ToString());
            }

          return result;
        }


[Flags]
 public enum ProfileTypeFlag : uint
    {
        None = 0,
        Customer = 1,
        Supplier = 2,
        Internal = 4,
        Delegate = 8,
        Master = 16,
        External = 32,
        CustomerMaster = Customer | Master | External,
        SupplierMaster = Supplier | Master | External
}
AFetter
  • 3,355
  • 6
  • 38
  • 62

3 Answers3

1

Just tweak your if statement slightly:

if ((role & r) == r && r != ProfileTypeFlag.None && role != r)

Or you could use HasFlag (equivalent to role & r == r):

if (role.HasFlag(r) && r != ProfileTypeFlag.None && role != r)

Basically, if the role includes the flag, it's not the None flag, and its not the role itself, then add it to the list.

With that in mind, you could change your whole function to:

public List<string> SetRoles(ProfileTypeFlag role)
{    
    return
        Enum.GetValues(typeof(ProfileTypeFlag))
            .Cast<ProfileTypeFlag>()
            .Where(r => r != ProfileTypeFlag.None)
            .Where(r => r != role)
            .Where(r => role.HasFlag(r))
            .Select(r => r.ToString())
            .ToList();
}

As @Lucas pointed out, the above solutions don't work quite correctly if your enum value contains compound flags.

One solution to this would be to remove flag values as you encounter them:

public List<string> SetRoles(ProfileTypeFlag role)
{    
    var result = new List<string>();

    foreach (ProfileTypeFlag r in Enum.GetValues(typeof(ProfileTypeFlag)))
    {
        if (role.HasFlag(r) && r != ProfileTypeFlag.None) 
        {
            result.Add(r.ToString());
            role &= ~r;
        }
    }

    return result;
}
Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307
  • I guess it will break on something like `ProfileTypeFlag.SupplierMaster | ProfileTypeFlag.Internal` – Lucas Trzesniewski Oct 30 '14 at 00:15
  • @LucasTrzesniewski: You're right, your solution might be better – Andrew Whitaker Oct 30 '14 at 00:21
  • On the other hand, mine requires all bits to be named, even if they're part of a compound value, or it'll insert the numerical value. – Lucas Trzesniewski Oct 30 '14 at 00:24
  • 1
    @AndrewWhitaker: actually, I prefer yours for readability. It just needs a little tweak: `return Enum.GetValues(typeof(ProfileTypeFlag)).Cast().Where(r => r != ProfileTypeFlag.None && ((int)r & ((int)r - 1)) == 0 && role.HasFlag(r)).Select(r => r.ToString()).ToList();` Note that I also prefer all the predicates in a single `Where()` method. It reads just as well, and involves fewer temp objects. – Peter Duniho Oct 30 '14 at 00:24
1

Here's a solution for you:

public static string GetFlagsStringFromUInt32Enum<TEnum>(TEnum value)
    where TEnum : struct
{
    var sb = new StringBuilder();

    for(var i = 0; i < 32; ++i)
    {
        var bit = (uint)1 << i;
        if (((uint)(object)value & bit) != 0)
            sb.Append((TEnum)(object)bit).Append(" | ");
    }

    if (sb.Length > 0)
        sb.Length -= 3;

    return sb.ToString();
}

Demo

This will work on enums based on uint like yours, I ddn't bother to implement a general solution.

Lucas Trzesniewski
  • 50,214
  • 11
  • 107
  • 158
0

To provide a slightly different approach, you could use this function to get the "set" enums:

static IEnumerable<Enum> GetFlags(Enum input)
{
    foreach (Enum value in Enum.GetValues(input.GetType()))
        if (input.HasFlag(value))
            yield return value;
}

Credit to @Greg (Iterate over values in Flags Enum?)

Then call it as such:

List<string> names = GetFlags(enumValue).Select(e => e.ToString()).ToList();
Community
  • 1
  • 1
BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117