Iterating through all values of an ORed enum variable...
-
Well, I don't know how to iterate through all POSSIBLE values of an enum, but given that you say you do, I think I have a solution for you.
Keys keys = Keys.Control | Keys.A; foreach(Keys key in POSSIBLEVALUES){ //however you're managing that if(keys & key) == key){ //the key contains this one! } }
Note: the enum value have to be lined up in powers of 2 in order for this to work properly so you can distinguish the values when you do a bitwise-or. The following is a bit of code that shows this:
enum Keys { A = 1, B = 2, C = 4, D = 8 } static void Main(string[] args) { Keys keys = Keys.A | Keys.B | Keys.D; if ((keys & Keys.A) == Keys.A) { Console.WriteLine("A"); } if ((keys & Keys.B) == Keys.B) { Console.WriteLine("B"); } if ((keys & Keys.C) == Keys.C) { Console.WriteLine("C"); } if ((keys & Keys.D) == Keys.D) { Console.WriteLine("D"); }
-
Hi, first of all I hope your enum behaves as a flags collection (and hence it better have the [Flags] attribute). There is a very nice trick to enumerate the individual bits in an int without using a loop that checks each and every bit:
int work=val; // copy the int whose bits need to be enumerated
while (work!=0) {
int singleBit=work & -work; // this has the lowest bit of work set
work=work^singleBit; // removes work's lowest bit set
... do whatever you need to do with singleBit
}Applied to enums, this leads to:
[Flags]
enum myFlags {a=1, b=2, c=4, d=8}public void Run() {
myFlags flags=myFlags.a | myFlags.c | myFlags.d;
int work=(int)flags; // copy the int whose bits need to be enumerated
while (work!=0) {
int singleBit=work & -work; // this has the lowest bit of work set
work=work^singleBit; // removes work's lowest bit set
myFlags mySingleFlag=(myFlags)singleBit;
log(mySingleFlag.ToString());
}
}this little example prints the characters a, c and d as it should. :)
Luc Pattyn
try { [Search CP Articles] [Search CP Forums] [Forum Guidelines] [My Articles] } catch { [Google] }
Great! How do people come up with this stuff?! I can never get myself to think outside of the box like that! :doh: Anywayz... Why didn't Microsoft implement this kind of iteration too?? It can be very useful in some cases where you want to create something generic...
-
Great! How do people come up with this stuff?! I can never get myself to think outside of the box like that! :doh: Anywayz... Why didn't Microsoft implement this kind of iteration too?? It can be very useful in some cases where you want to create something generic...
Hi, casting back and forth between an enum and an int is standard practice; examples are everywhere, even in MS documentation. Tricky code snippets to manipulate bits (and do many other things), have been discovered one by one over time; I started my collection of those many years ago... I even have some books on them, some work only in assembly code, some only on specific processors, and some (like the current one) can be applied everywhere even in a high-level language. :)
Luc Pattyn
try { [Search CP Articles] [Search CP Forums] [Forum Guidelines] [My Articles] } catch { [Google] }
-
Great! How do people come up with this stuff?! I can never get myself to think outside of the box like that! :doh: Anywayz... Why didn't Microsoft implement this kind of iteration too?? It can be very useful in some cases where you want to create something generic...
shyagam wrote:
Why didn't Microsoft implement this kind of iteration too??
You are absolutely right: they could have provided a GetEnumerator() method that would throw an exception if the enum is not [Flags], and returns an enumeration of the enum values that are present in the enum at hand. But they didnt. :)
Luc Pattyn
try { [Search CP Articles] [Search CP Forums] [Forum Guidelines] [My Articles] } catch { [Google] }
-
shyagam wrote:
Why didn't Microsoft implement this kind of iteration too??
You are absolutely right: they could have provided a GetEnumerator() method that would throw an exception if the enum is not [Flags], and returns an enumeration of the enum values that are present in the enum at hand. But they didnt. :)
Luc Pattyn
try { [Search CP Articles] [Search CP Forums] [Forum Guidelines] [My Articles] } catch { [Google] }
-
Hi, first of all I hope your enum behaves as a flags collection (and hence it better have the [Flags] attribute). There is a very nice trick to enumerate the individual bits in an int without using a loop that checks each and every bit:
int work=val; // copy the int whose bits need to be enumerated
while (work!=0) {
int singleBit=work & -work; // this has the lowest bit of work set
work=work^singleBit; // removes work's lowest bit set
... do whatever you need to do with singleBit
}Applied to enums, this leads to:
[Flags]
enum myFlags {a=1, b=2, c=4, d=8}public void Run() {
myFlags flags=myFlags.a | myFlags.c | myFlags.d;
int work=(int)flags; // copy the int whose bits need to be enumerated
while (work!=0) {
int singleBit=work & -work; // this has the lowest bit of work set
work=work^singleBit; // removes work's lowest bit set
myFlags mySingleFlag=(myFlags)singleBit;
log(mySingleFlag.ToString());
}
}this little example prints the characters a, c and d as it should. :)
Luc Pattyn
try { [Search CP Articles] [Search CP Forums] [Forum Guidelines] [My Articles] } catch { [Google] }
-
Hello, So your solution would mean to iterate threw the enum members and do the bit test?
Luc Pattyn wrote:
(and hence it better have the [Flags] attribute).
Is there a rule in the Framework when they use the Attribute?
All the best, Martin
Hi Martin, [Flags] or [FlagsAttribute] is explained in the FlagsAttribute page on MSDN. It is rather long and not very important. One thing is it influences how ToString() works, which returns symbolic names when possible; with Flags it returns a combintation of one or more symbolic names, without Flags it does not. Unfortunately, when specifying [Flags] it still is possible to assign values that are NOT powers of 2 as in: [FlagsAttribute] enum myFlags3 { a=1, b=2, c=15, d=8 } In fact they do recommend you do this with the example Read=1, Write=2, ReadWrite=3 but I would like the possibility to get an error when I do this accidentally. Greetings. :)
Luc Pattyn
try { [Search CP Articles] [Search CP Forums] [Forum Guidelines] [My Articles] } catch { [Google] }
-
Hello, So your solution would mean to iterate threw the enum members and do the bit test?
Luc Pattyn wrote:
(and hence it better have the [Flags] attribute).
Is there a rule in the Framework when they use the Attribute?
All the best, Martin
Hi,
Martin# wrote:
So your solution would mean to iterate threw the enum members and do the bit test?
No, my code does not even has to know what all the possible enum values are; the only thing it is interested in is the fact that they are Flags, not arbitrary values. Watch my while-loop carefully, it does not perform an Enum.GetValues() and it does not iterate over the bits (as in for(int bit=0; bit<32; bit++)...); it automatically loops a number of times, equal to the number of bits set in the enum value ! :)
Luc Pattyn
try { [Search CP Articles] [Search CP Forums] [Forum Guidelines] [My Articles] } catch { [Google] }
-
Hi,
Martin# wrote:
So your solution would mean to iterate threw the enum members and do the bit test?
No, my code does not even has to know what all the possible enum values are; the only thing it is interested in is the fact that they are Flags, not arbitrary values. Watch my while-loop carefully, it does not perform an Enum.GetValues() and it does not iterate over the bits (as in for(int bit=0; bit<32; bit++)...); it automatically loops a number of times, equal to the number of bits set in the enum value ! :)
Luc Pattyn
try { [Search CP Articles] [Search CP Forums] [Forum Guidelines] [My Articles] } catch { [Google] }
-
Hello experts, Is there a way to iterate through all of the values assigned to an enum (in my case the
Keys
enum)? Something like:Keys keys = Keys.Control | Keys.A; foreach (Something goes here) // Do something with the key
I know how to iterate through all POSSIBLE values of an enum, but I would like to iterate through all ASSIGNED values of an enum variable. Thanks in advance, Shy.FYI, here's another way to do it w/ Enum.Parse method, which is undoubtably slower and takes more memory, but improves readability (maybe :-D )
[Flags] enum Keys { A = 1, B = 2, C = 4, D = 8 } static void Main(string[] args) { Keys keys = Keys.A | Keys.B | Keys.D; string[] strKeys = keys.ToString().Split(','); foreach(string key in strKeys){ Keys newKey = (Keys)Enum.Parse(keys.GetType(),key); Console.WriteLine(newKey.ToString()); } }