tags:

views:

90

answers:

3

I have a flagged enum and need to retrieve the names of all values set on it.

I am currently taking advantage of the enum's ToString() method which returns the elements comma-separated.

    public void SetRoles(Enums.Roles role)
    {
        IList<Entities.Role> roleList = role.ToString("G").Split(',')
            .Select(r => new Entities.Role(r.Trim()))
            .ToList();
    ...
    }

I'm sure there must be a better way than this.

+2  A: 

Why do you need a list? Everything is already stored in the flags:

[Flags]
enum Roles
{
    Read = 0x1,
    Write = 0x2,
    Delete = 0x4,
}

Then assign roles:

var roles = Roles.Read | Roles.Write;

And whenever you need to check if a given role has been you don't need to look in a list, but simply look in the roles enumeration:

if ((roles & Roles.Read) == Roles.Read)
{
    // The user has read permission
}
if ((roles & Roles.Write) == Roles.Write)
{
    // The user has write permission
}
Darin Dimitrov
That is how the application is using it. However, this is more of a persistance concern. I'd rather leave this method unaware of what values the enum might contain.
David Neale
If it is for persistence all you need to store is a single integer representing the flags because this integer allows you to later extract all the roles. No need to store lists. Otherwise the `[Flags]` is kind of unnecessary if you are going to keep lists of roles. You will also gain a few bytes of storage media :-)
Darin Dimitrov
However, sometimes it's important to keep the stored data in a somewhat human-readable format. In that case, Enum.Parse can handle concatenated enum values just fine, similarly to how ToString() outputs them. So `Enum.Parse(typeof(Roles), "Read, Write")` will result in the correct Read | Write value. Actually I'll write an answer with this info.
Alex Paven
@David, the whole point of [`Flags`](http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx) is that it allows you to store multiple values into a single integer.
Darin Dimitrov
@Darin. My authorisation strategy has somewhat changed and you're right, there isn't any need for this. However, could there not be a time when somebody might like to map a flagged enum value to a database record or similar?
David Neale
I agree with David. While the power of flag enums is to concatenate multiple settings into one value, sometimes being human-readable is better than being compact. What's the value of 1064? OK, 1024 store it as "Read, Write, Delete" and someone dealing with raw data can understand it at a glance.
KeithS
+3  A: 

Good question!

I can't think of anything better than:

public void SetRoles(Enums.Roles role)
{
  List<string> result = new List<string>();
  foreach(Roles r in Enum.GetValues(typeof(Roles))
  {
    if ((role & r) != 0) result.Add(r.ToString());
  }
}
Grzenio
+1  A: 

Enum.Parse will handle the concatenated values outputted by ToString just fine. Proof using the Immediate window:

? System.Enum.Parse(typeof(System.AttributeTargets), "Class, Enum")
Class | Enum

(the second line is the output, which is different in the debugger/immediate window from the generic Enum.ToString() output).

Alex Paven