Typy Enum są ładnym rozwiązaniem służącym do definiowania stałych. Zamiast przekazywać nic nie mówiącą liczbę do funkcji, możemy zdefiniować enum i przekazać np. TextAlignment.Left – z pewnością poprawi to czytelność kodu. Czasami jednak chcemy przekazać dwa enumy naraz lub dowolną ich kombinację. W tym celu musimy skorzystać z tzw. flag. Zacznijmy od razu od przykładu:
[Flags] enum Days { None = 0, Sunday = 1, Monday = 2, Tuesday = 4, Wednesday = 8, Thursday = 16, Friday = 32, Saturday = 64 }
Pierwszą kwestią jest atrybut Flags. Jak widać określiłem z góry wartości dla poszczególnych enum – jest to niezbędne, jednak wyjaśnię to dopiero na końcu post’a. Najpierw zobaczmy co dzięki flagom możemy uzyskać (źródło MSDN):
// Initialize with two flags using bitwise OR. Days meetingDays = Days.Tuesday | Days.Thursday; // Set an additional flag using bitwise OR. meetingDays = meetingDays | Days.Friday; Console.WriteLine("Meeting days are {0}", meetingDays); // Output: Meeting days are Tuesday, Thursday, Friday // Remove a flag using bitwise XOR. meetingDays = meetingDays ^ Days.Tuesday; Console.WriteLine("Meeting days are {0}", meetingDays);
Operator OR (w C# |) służy do tworzenia kombinacji z poszczególnych typów. Z kolei XOR (W C# ^) odpowiedzialny jest za usuwanie enuma z sumy. Można operatory utożsamiać z + oraz –, jednak na końcu zobaczymy jak to wygląda dokładnie z punktu widzenia algebry Bool’a. Warto również, że dzięki atrybutowi Flags, kompilator rozpoznaje złączenia i wyświetla wszystkie elementy (a nie liczbę utworzoną przez OR).
W kodzie jednak dużo częściej będziemy musieli sprawdzić czy dana suma zawiera konkretny element (rzadko kiedy wyświetlamy enum’y jak pokazano w kodzie wyżej). Niezbędny jest zatem mechanizm umożliwiający sprawdzenie czy dany element znajduje się zbiorze. Służy do tego operator AND:
bool test = (meetingDays & Days.Thursday) == Days.Thursday; Console.WriteLine("Thursday {0} a meeting day.", test == true ? "is" : "is not");
Przyjrzyjmy się teraz wartościom binarnym enuma:
00000000 0
00000001 1
00000010 2
00000100 4
00001000 16
00010000 32
00100000 64
Złączmy dwie ostatnie wartości tzn:
00010000 OR 00100000 = 00110000
Jak widać żaden bit nie został napisany (dzięki wykorzystanemu kodowaniu). Zobaczmy jeszcze operator AND służący do testowania czy dany element znajduje się w zbiorze:
00110000 AND 00100000 == 00100000
Gdybyśmy źle zakodowali wartości enum’a, niektóre bity mogłyby się napisać. Wykorzystując prostą algebrę można w sprytny sposób łączyć liczby.