2

I have the following flags Enum:

[Flags]
public enum RoleModels {
  Master = 1 << 0,
  Editor = 1 << 1,
  Member = 1 << 2
}

And I have a RoleModels variable and a list of strings:

var roles1 = RoleModels.Master | RoleModels.Member;

List<String> rolesStrings = new List<String> { "mAster", "Member" }

I would like to check if all rolesStrings are in roles.

The check should be case insensitive ... In this case it will be true.

I was trying to convert the strings to one enum:

var roles2 = (RoleModels)rolesStrings.Aggregate((a, b) => a | b);

And then check, somehow, if all roles2 are in roles1.

But I wasn't able to make this work ...

Could someone, please, help me out?

Thank You, Miguel

Igor Kustov
  • 3,228
  • 2
  • 34
  • 31
Miguel Moura
  • 36,732
  • 85
  • 259
  • 481
  • is that `{ "mAster", "Member" }` or did you mean `{ "Master", "Member" }` – MethodMan Apr 28 '14 at 15:59
  • 2
    @DJKRAZE: He explicitly said the check was case insensitive so it should work with either. – Chris Apr 28 '14 at 16:00
  • 1
    then he can try something like this in my opinion `bool result = Enum.GetNames(typeof(RoleModels)).Contains("rolesStrings[0]");`..etc using an || condition in his check as well if he likes – MethodMan Apr 28 '14 at 16:02
  • @DJKRAZE - Post that as an answer. – Bobson Apr 28 '14 at 16:14
  • @Bobson my remark does not qualify as an answer because it does not take in account the case insensitivity if otherwise I would – MethodMan Apr 28 '14 at 17:29

4 Answers4

4

You can do it like this:

var roles1 = RoleModels.Master | RoleModels.Member;
List<String> rolesStrings = new List<String> { "mAster", "Member" }

bool hasFlag = true;
foreach (var role in rolesStrings)
{
    RoleModels enumValue;

    if (!(Enum.TryParse(role,true, out enumValue) && roles1.HasFlag(enumValue)))
    {
        hasFlag = false;
        break;
    }
}

Here is the fiddle

Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • 2
    There is a TryParse that ignores case that would be easier (and more robust) than your conversions. http://msdn.microsoft.com/en-us/library/dd991317(v=vs.110).aspx – Chris Apr 28 '14 at 16:06
  • 1
    @Chris ah, you right.I completely forgot that thanks – Selman Genç Apr 28 '14 at 16:08
  • no prob. I didn't know it was there but thought surely there must be a way and found it. :) – Chris Apr 28 '14 at 16:22
2

A LINQ-ified version of Selman22's answer:

var roles1 = RoleModels.Master | RoleModels.Member;
List<String> rolesStrings = new List<String> { "mAster", "Member" };

RoleModels enumValue;
var valid = rolesStrings.All(r => (Enum.TryParse(r, true, out enumValue) && 
                                  roles1.HasFlag(enumValue)));

Note that All() will return true if rolesStrings is empty, because all 0 elements are valid.

Bobson
  • 13,498
  • 5
  • 55
  • 80
1

My version of your code with minimal modifications:

var roles1 = RoleModels.Master | RoleModels.Member;

List<String> rolesStrings = new List<String> { "mAster", "Member", "editor" };

var roles2 = rolesStrings.Select(x=>(RoleModels)Enum.Parse(typeof(RoleModels),x, true)).Aggregate((a, b) => a | b);

if ((roles1&roles2)==roles2)
{
    Console.WriteLine(String.Format("{0} (roles2) are in {1} (roles1)", roles2, roles1));
}
else
{
    Console.WriteLine(String.Format("{0} (roles2) are not in {1} (roles1)", roles2, roles1));
}

Key things to note are that for roles2 I've used Enum.Parse to convert the sdtrings to their enum values. This will fail if there is no matching enum (this may be important if you are getting unvalidated data).

I then aggregate them and use (roles1&roles2)==roles2 to check that everything in roles 2 is in roles 1. This works because any bit in roles2 that is not in roles 1 will not be set when & is applied so it will no longer match roles2 when compared.

If you need to do validation of the input values you may be better off using a more verbose method such as others suggested but I provide this solution as the closest "fix" to the method you were trying rather than presenting you with an entirely different method.

Chris
  • 27,210
  • 6
  • 71
  • 92
0

Use Enum.GetNames:

var rolesStrings = new List<String> { "mAster", "member" };
var enums =  Enum.GetNames(typeof(RoleModels));
var result = rolesStrings.All(roleString => enums.Any(enumString => String.Equals(roleString,enumString, StringComparison.OrdinalIgnoreCase));
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • Redundant ToList and Containts is not case-insensitiv. – CSharpie Apr 28 '14 at 16:16
  • I checked the code in LINQPad and it works fine. Contains is case sensitive – Yuval Itzchakov Apr 28 '14 at 16:17
  • Yes and it is supposed to be INsensitiv – CSharpie Apr 28 '14 at 16:17
  • Im sorry, case insensitive. It matches the list – Yuval Itzchakov Apr 28 '14 at 16:18
  • 1
    I think it is the wrong way round too. It should be checking that all values in rolestrings are in roles1. This is just checking if any of the rolestrings match one of the RoleModels names (not using roles1 at all). It isn't case insensitive, it just doesn't actually care about "mAster" because "Member" matches and the any means it doesn't matter about the rest. You'll want to use an `All` in your code to get it to work properly. – Chris Apr 28 '14 at 16:20
  • You're right, i checked it agains't Any instead of All. – Yuval Itzchakov Apr 28 '14 at 16:21
  • This fails on the case of `List rolesStrings = new List { "mAster", "Editor"};`. That should return false, because not all of the strings are in the `roles1` enum. – Bobson Apr 28 '14 at 16:51
  • Why should it return false? Editor and Master are part of the enum. the check is case insensitive – Yuval Itzchakov Apr 28 '14 at 16:58
  • 1
    @YuvalItzchakov - From the question: `I would like to check if all rolesStrings are in roles. ` and `And then check, somehow, if all roles2 are in roles1.` – Bobson Apr 28 '14 at 17:04