24

I have the following enumeration of membership roles:

public enum RoleName
{
    RegisteredUser,
    Moderator,
    Administrator,
    Owner
}

I want to be able to fetch all roles greater than or equal to a given role.

For instance I input Administrator and I get an IEnumerable with RoleName.Administration and RoleName.Owner

Something of this sort:

public static void AddUserToRole(string username, RoleName level)
{
    var roles = Enum.GetValues(typeof(RoleName)).Cast<R>().ToList().Where(role => level > role);

    foreach (var role in roles)
    {
        Roles.AddUserToRole(username, role);
    }
}
1
  • 1
    considering that enum as default is of INT type, isn't enough to compare values against filter int? Commented Jul 24, 2011 at 15:53

7 Answers 7

25

Probably depending on version of .NET. But this works very well for me:

There is no need to convert or to use special tricks. Just compare with the usual operators:

using System;

enum Test { a1, a2, a3, a4 }

class Program
{
    static void Main(string[] args)
    {
        Test a = Test.a2;

        Console.WriteLine((a > Test.a1));
        Console.WriteLine((a > Test.a2));
        Console.WriteLine((a > Test.a3));
        Console.WriteLine((a > Test.a4));

        Console.ReadKey();
    }
}

Output:

True
False
False
False
Sign up to request clarification or add additional context in comments.

Comments

21

You can use the following helper method to give you a set of roles allowed for a given role:

    private IEnumerable<RoleName> AllAllowedRoles(RoleName level)
    {
        return Enum.GetValues(typeof(RoleName)).Cast<RoleName>().Where(role => level >= role);
    } 

And then assign all of them to the user.

Comments

7

in order to have a better definition of which role is greater than the other you need to assign numeric values to your roles like this:

public enum RoleName
{
    RegisteredUser = 2,
    Moderator = 4,
    Administrator = 8,
    Owner = 16
}

Now if you cast any instance of type RoleName to (int) you will get the numeric value and therefore you will be able to compare them against each other.

Note:
1. Here I use powers of 2 as values to allow combining RoleNames using bit-wise operators.

3 Comments

Wrong; you don't need to assign any values.
true that but as I said: in order to have a "better definition". otherwise you can easily get confused. but by giving them values you can always quickly judge that.
Not sure using flags here is a good idea. most of the combinations are meaningless eg. Owner | RegisteredUser.
2

went with this:

    public static void AddUserToRole(string username, RoleName level)
    {
        var roles = RolesLesserThanOrEqualTo(level);

        foreach (var role in roles)
        {
            Roles.AddUserToRole(username, role.Name());
        }
    }

    public static IEnumerable<RoleName> RolesLesserThanOrEqualTo(RoleName level)
    {
        return Enum.GetValues(typeof(RoleName)).Cast<RoleName>().Where(role => level >= role);
    }

Comments

0

Your code is exactly correct, except that you need to Cast<int>() and you don't need ToList().

Comments

0
public enum RoleName : int
{
    RegisteredUser = 7,
    Moderator = 8,
    Administrator = 9,
    Owner = 10
}

 public List<RoleName> GetGreaterOrEqual(RoleName role)
    {
        List<RoleName> list = new List<RoleName>();
        foreach (RoleName rn in Enum.GetValues(typeof(RoleName)))
        {
            if(rn >= role)
                list.Add(rn);
        }
        return list;
    }

You could check this out Can you loop through all enum values?

Comments

0

You have to take into consideration the underlying type of the enum. Thus:

static IEnumerable<T> Get<T>(T value) where T : struct {
    Type underlyingType = Enum.GetUnderlyingType(typeof(T));
    var compareToMethod = underlyingType.GetMethod(
                              "CompareTo",
                              new[] { underlyingType }
                          );
    var values = Enum.GetValues(typeof(T));
    for (int index = 0; index < values.Length; index++) {
        int comparison = (int)compareToMethod.Invoke(
            Convert.ChangeType(value, underlyingType),
            new object[] { values.GetValue(index) }
        );
        if (comparison >= 0) {
            yield return (T)values.GetValue(index);
        }
     }
 }

I didn't feel like trying to come up with a good name, but this works:

var largerValues = Get<RoleName>(RoleName.Moderator);
foreach(var largerValue in largerValues) {
    Console.WriteLine(largerValue);
}

2 Comments

Is reflection really the best way to go?
@Nico: If you want it to be general, yes. If you want it ONLY for RoleName, no.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.