Click here to Skip to main content
15,885,743 members
Please Sign up or sign in to vote.
4.60/5 (9 votes)
See more:
I have an enum with flags attribute. How to check if int is in enum. Enum.IsDefiend returns false if check for example two ored values from enum.
Thanks in advance.
Posted
Comments
#realJSOP 10-May-11 14:52pm    
5 - Great question, btw.
Rick Shaub 10-May-11 15:08pm    
I agree it made me have to think outside the box.

This is how to do it:

C#
static bool IsIntInEnum(System.Type enumType, int value) {
   if (enumType == null) return false;
   if (!enumType.IsEnum) return false;
   var values = System.Enum.GetValues(enumType);
   if (values == null) return false;
   if (values.Length < 1) return false;
   foreach (object enumvalue in values)
       if (enumvalue is int) break; else return false;
   System.Predicate<int> predicate = (item) => { return (item & value) > 0; };
   return System.Array.Exists<int>((int[])values, predicate);
}


It is important to understand that the attribute System.FlagsAttribute only affects the string presentation of the value via ToString or string.Format. Also, with or without this attribute, enumeration members does not have to be powers of two. There are quite practical applications (in Windows API, for example) when the set of enumeration members represents the mixture of bit set values with, say, a set of consecutive values.

—SA
 
Share this answer
 
v5
Comments
Rick Shaub 10-May-11 21:54pm    
I don't think this solves the OP's problem.
Sergey Alexandrovich Kryukov 10-May-11 22:39pm    
First, it's not yet complete. I have another variant, secondly -- arguments, please!
(I'll notify when it's done.)
--SA
Sergey Alexandrovich Kryukov 10-May-11 22:42pm    
Now it's done.
As far as I can see, this is the only correct solution on this page. You can test it.
--SA
Rick Shaub 10-May-11 23:05pm    
The OP wants to check if an int is bitwise OR of two or more flags, or a value in his enum. This solution will not do that. This type of iterative approach is going to be O(2^n) because you have to check all combinations of flags before declaring the result false. You could build a table and perform a binary search, which would be probably optimal timewise. Here's a simple test case:

[Flags]
public enum FlagEnum
{
one=1,
two=2,
four=4,
eight = 8,
sixteen =16,
thirtytwo = 32

}
private void button1_Click(object sender, EventArgs e)
{
bool orly = IsIntInEnum(typeof(FlagEnum),(int)(FlagEnum.one|FlagEnum.thirtytwo));

}
Sergey Alexandrovich Kryukov 10-May-11 23:14pm    
No, it won't, I agree. The question is formulated the way I'm not sure this is what is asked.

You see, FlagsAttribute has nothing to do with bitwise operations except presentation of the value by ToString. Moreover, enum members do not have to be the powers of 2. Perhaps this is the illusion of OP that it explains it. Until OP mentions explicitly a bit in a bit set, this is not either incorrectly formulated question or something what I did.

Finding if a bit is in enum is another simple task but I don't want to solve it until OP clear the question.

Anyway, thank you for this note, I'll modify the answer.
--SA
I know you've already accepted an answer, but here's a more math-oriented way (more code, too):

C#
bool IsFlagsValid(Type t, int value)
{
    bool valid = false;
    if (t.IsEnum)
    {
        valid = true;
        int maxBit = Convert.ToInt32(Math.Pow(2, Math.Ceiling(Math.Log(value)/Math.Log(2)))) >> 2;
        int i = 1;
        do
        {
            if (0 != (value & (1 << i)))
            {
                valid = (Enum.IsDefined(t, 1 << i));
                if (!valid)
                {
                    break;
                }
            }
            i++;
        } while (maxBit > i);
    }
    return valid;
}


Call it like this:

C#
if (IsFlagsValid(MyFlagsEnum, 25))
{
    // do something if the value was valid
} 
 
Share this answer
 
v3
Comments
yesotaso 10-May-11 15:24pm    
What if... (just a thought)
[FlagsAttribute]
public enum psychoEnum
{ A = 0, B = 3, C = 4, D = 8 ... }
#realJSOP 10-May-11 15:33pm    
For a Flags enum, 3 is not a valid ordinal, because if the enum value is set to 3, that means ordinals 1 and 2 are indicated. That's the way Flags enums work.
yesotaso 10-May-11 15:50pm    
Well yes 3 is not valid but it just compiles and runs :) Though I'd never do such thing knowingly.
Sergey Alexandrovich Kryukov 10-May-11 20:05pm    
3 is valid! FlagsAttribute only effect naming in ToString.
--SA
yesotaso 10-May-11 20:43pm    
Yes sir, syntactically and semantically but not figuratively.
Edit: I mean it boils down to habits again. Use of powers of 2 - checking against "logical and" etc..
Here's an article showing how to do what you are asking: 'Extending' the Enum Class to Validate the Enum Values with the Flags Attribute[^]. Unfortunately, this is not an easy fix.

Another slightly hacky alternative would be to take the result of .ToString() from your enum and call Int32.TryParse. If the result is true, that means the value is returning as an integer string, not a named enum or combination of enums.

C#
//Example
int myThrowAwayInt;
MyEnum MyEnumValue = (MyEnum)2|8;
bool notDefined = Int32.TryParse(MyEnumValue.ToString(), out myThrowAwayInt);
if(notDefined)
{
    //This enum value is not defined
}
 
Share this answer
 
v2
Comments
#realJSOP 10-May-11 14:33pm    
Check out my version. :)
Sergey Alexandrovich Kryukov 10-May-11 20:16pm    
Nah! Please see correct solution.
--SA
Rick Shaub 10-May-11 23:09pm    
See my comment. Also note that I did not down vote.
Given the following enum I think what your looking for is DaysEnumNeedsFlags.Saturday.HasFlag(DaysEnumNeedsFlags.Saturday)

C#
[FlagsAttribute]
public enum DaysEnumNeedsFlags
{
    None = 0,
    Monday = 1,
    Tuesday = 2,
    Wednesday = 4,
    Thursday = 8,
    Friday = 16,
    Saturday = 32,
    Sunday = 64,
    WeekDays = Monday | Tuesday | Wednesday | Thursday | Friday,
    Weekend = Saturday | Sunday
}
 
Share this answer
 
Heres an enum in C++/CLI that I am using to determine if columns on a grid have changed

[Flags] enum class m_FlagBits
{
        EXPIRY_ID = 1,
        DESCRIPTION = 2,
        EXPIRY_TYPE = 4,
        UNIT_ID = 8,
        FIXED_INTERVAL_ID = 16,
        DAY = 32,
        NUMBER_OF_INTERVAL_UNITS = 64,
        VALID_FROM = 128,
        VALID_TO = 256
};
m_FlagBits m_ElementList;




Make sure none of the values are set when I enter a row:
m_ElementList = m_ElementList & ~ m_FlagBits::EXPIRY_ID;
m_ElementList = m_ElementList & ~ m_FlagBits::EXPIRY_TYPE;
m_ElementList = m_ElementList & ~ m_FlagBits::DESCRIPTION;
m_ElementList = m_ElementList & ~ m_FlagBits::UNIT_ID;
m_ElementList = m_ElementList & ~ m_FlagBits::DAY;
m_ElementList = m_ElementList & ~ m_FlagBits::NUMBER_OF_INTERVAL_UNITS;
m_ElementList = m_ElementList & ~ m_FlagBits::FIXED_INTERVAL_ID;
m_ElementList = m_ElementList & ~ m_FlagBits::VALID_FROM;
m_ElementList = m_ElementList & ~ m_FlagBits::VALID_TO;




Setting one of them after changing a value:
m_ElementList = m_ElementList | m_FlagBits::EXPIRY_ID; 


Checking if one of them has been used
if (static_cast<int>(m_ElementList) & static_cast<int>(m_FlagBits::EXPIRY_ID))
{
   //Do Stuff like update the corresponding table
}
 
Share this answer
 
Once again, this is an answered question, but here's a hack-ish way to do this in very few lines of code. Full example below:

C#
[Flags]
enum Nums
{
    One = 1,
    Two = 2,
    Four = 4
}

static void Main()
{
    Console.WriteLine(IsValidFlag<Nums>(3)); //true
    Console.WriteLine(IsValidFlag<Nums>(8)); //false
}

private static bool IsValidFlag<T>(int x) where T: struct
{
    return x.ToString() != ((T)(object)x).ToString();
}
 
Share this answer
 
You can check an or agains all numbers in decending order against your value and see if the result is zero.

C#
static bool IsInNumbers(Type EnumType, int number) {
    var vals = Enum.GetValues(typeof(Numbers)).Cast<int>();
    for (int i = vals.Count() - 1; i >= 0; i--) {
        if ((vals.ElementAt(i) & number) == vals.ElementAt(i))
            number -= vals.ElementAt(i);
    }
        return number==0;
}</int>



comnplete example below

C#
class Program {
    [Flags]
    public enum Numbers {
        Zero = 0,
        One = 1,
        Two = 2,
        Three = 4,
        Four = 8
    }
    static void Main(string[] args) {
        Type MyenumType = typeof(Numbers);
        Console.WriteLine(IsInNumbers(MyenumType, 1));
        Console.WriteLine(IsInNumbers(MyenumType, (int)(Numbers.Four | Numbers.Three)));
        Console.WriteLine(IsInNumbers(MyenumType, 9));
        Console.WriteLine(IsInNumbers(MyenumType, 23));
        Console.Read();
    }

    static bool IsInNumbers(Type EnumType, int number) {
        var vals = Enum.GetValues(typeof(Numbers)).Cast<int>();
        for (int i = vals.Count() - 1; i >= 0; i--) {
            if ((vals.ElementAt(i) & number) == vals.ElementAt(i))
                number -= vals.ElementAt(i);
        }
            return number==0;
    }
}
 
Share this answer
 
Comments
cechode 10-May-11 12:55pm    
ouch a 1 vote ( heh )

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900