-
[ Pobierz całość w formacie PDF ]
Analiza
Dodanie atrybutu Flags do deklaracji typu wyliczeniowego powoduje, że określone elementy
typu są traktowane jako indywidualne flagi bitowe, dla których można wykonywać bitową
operacjÄ™ OR. Zastosowanie typu wyliczeniowego oznaczonego atrybutem Flags niczym nie
różni się od stosowania standardowego typu wyliczeniowego. Należy zwrócić uwagę, że brak
oznaczenia typu wyliczeniowego atrybutem Flags nie spowoduje zgłoszenia wyjątku ani
powstania błędu kompilacji nawet wtedy, gdy elementy typu wyliczeniowego będą wyko-
rzystane jako flagi bitowe.
Dodanie atrybutu Flags daje dwie korzyści. Po pierwsze, w przypadku oznaczenia typu
wyliczeniowego atrybutem Flags metody ToString oraz ToString("G") zwracajÄ… ciÄ…g zna-
ków składający się z nazw stałych rozdzielonych przecinkami. W innym razie te dwie metody
zwracają liczbową reprezentację elementu typu wyliczeniowego. Należy zwrócić uwagę, że
metoda ToString("F") zwraca ciąg znaków składający się z nazw stałych rozdzielonych prze-
cinkami, niezależnie od tego, czy określony typ wyliczeniowy oznaczono atrybutem Flags
czy nie. Aby uzyskać wskazówkę dotyczącą sposobu działania tej metody, można zapoznać
siÄ™ z opisem typu formatowania "F" w tabeli 1.2 zamieszczonej w recepturze 1.16.
Druga korzyść polega na tym, że w przypadku natknięcia się na typ wyliczeniowy w analizo-
wanym kodzie, można łatwiej ocenić, do czego programista chciał go wykorzystać. Jeśli jawnie
zdefiniował go z atrybutem Flags, możemy stosować jego wartości jako maski bitowe.
Typ wyliczeniowy oznaczony atrybutem Flags można interpretować jako wartość pojedynczą
lub jako kilka wartości połączonych w jedną. Jeśli chcemy jednocześnie przekazać kilka języków,
możemy wykorzystać następujący kod:
Language lang = Language.CSharp | Language.VBNET;
Zmienna lang jest teraz równa bitowym wartościom dwóch elementów typu wyliczeniowego
po poddaniu ich operacji OR. W wyniku wykonania tej operacji uzyskamy wartość 3, tak jak
pokazano poniżej:
Language.CSharp 0001
Language.VBNET.....0010
Po wykonaniu OR 0011
Elementy typu wyliczeniowego przekształcono na liczby dwójkowe, a następnie wykonano
operację OR. W jej wyniku uzyskano wartość 0011, czyli 3 w systemie dziesiętnym. Dla kom-
pilatora ta wartość to zarówno dwa elementy typu wyliczeniowego po wykonaniu operacji OR
(Language.CSharp | Language.VBNET), jak pojedyncza wartość 3.
Aby sprawdzić, czy w zmiennej typu wyliczeniowego włączono określoną flagę, można sko-
rzystać z bitowego operatora AND (&) w następujący sposób:
Language lang = Language.CSharp | Language.VBNET;
if((lang & Language.CSharp) == Language.CSharp)
Console.WriteLine("Zmienna zawiera flagę odpowiadającą językowi C#");
else
Console.WriteLine("Zmienna nie zawiera flagi odpowiadającej językowi C#");
Wykonanie powyższego kodu spowoduje wyświetlenie tekstu Zmienna zawiera flagę odpowia-
dającą językowi C#. Wykonanie operacji AND dla zmiennej lang i elementu Language.CSharp
zwróci zero, jeśli w zmiennej lang nie włączono flagi odpowiadającej językowi C#, lub wartość
1.20. Zastosowanie elementów typu wyliczeniowego w masce bitowej | 53
Language.CSharp w przypadku, gdy w zmiennej lang włączono tę flagę. Wykonanie operacji
AND dla dwójkowych reprezentacji obu wartości można zapisać w sposób następujący:
Language.CSharp | Language.VBNET 0011
Language.CSharp 0001
Wynik operacji AND 0001
Dokładniej problem ten opisano w recepturze 1.21.
W niektórych przypadkach definicja typu wyliczeniowego rozrasta się do sporych rozmiarów.
W przypadku typu Language można wprowadzić odpowiedniki wielu różnych języków, tak
jak pokazano poniżej:
[Flags]
enum Language
{
CSharp = 0x0001, VBNET = 0x0002, VB6 = 0x0004, Cpp = 0x0008,
FortranNET = 0x0010, JSharp = 0x0020, MSIL = 0x0080
}
Aby utworzyć wartość typu wyliczeniowego Language, która reprezentuje wszystkie języki,
trzeba by wykonać operację OR dla wszystkich wartości typu:
Language lang = Language.CSharp | Language.VBNET | Language.VB6;
Zamiast tego można dodać nową wartość All do typu wyliczeniowego obejmującą wszystkie
języki. Można to zrobić w następujący sposób:
[Flags]
enum Language
{
CSharp = 0x0001, VBNET = 0x0002, VB6 = 0x0004, Cpp = 0x0008,
FortranNET = 0x0010, JSharp = 0x0020, MSIL = 0x0080,
All = (CSharp | VBNET | VB6 | Cpp | FortranNET | JSharp | MSIL)
}
Mamy teraz nową wartość typu wyliczeniowego All, która obejmuje wszystkie jego wartości.
Zwróćmy uwagę na to, że istnieją dwa sposoby reprezentacji wszystkich wartości typu wyli-
czeniowego. Druga z nich jest znacznie bardziej czytelna. Niezależnie od wybranej metody
w przypadku dodania lub usunięcia elementów typu wyliczeniowego trzeba odpowiednio
zmodyfikować wartość reprezentującą wszystkie wartości.
W podobny sposób można wprowadzić wartości odpowiadające określonym podzbiorom
wartości typu wyliczeniowego, na przykład:
[Flags]
enum Language
{
CSharp = 0x0001, VBNET = 0x0002, VB6 = 0x0004, Cpp = 0x0008,
CobolNET = 0x000F, FortranNET = 0x0010, JSharp = 0x0020,
MSIL = 0x0080,
All = (CSharp | VBNET | VB6 | Cpp | FortranNET | JSharp | MSIL),
VBOnly = (VBNET | VB6),
NonVB = (CSharp | Cpp | FortranNET | JSharp | MSIL)
}
Mamy teraz dwa dodatkowe elementy typu wyliczeniowego: jeden odpowiadający wyłącznie
językom rodziny Visual Basic (Language.VBNET oraz Language.VB6) i drugi, który odpowiada
innym językom niż VB).
54 | Rozdział 1. Liczby i typy wyliczeniowe
1.21. Sprawdzanie, czy ustawiono jednÄ… czy kilka flag
w danych typu wyliczeniowego
Problem
Trzeba sprawdzić, czy w zmiennej typu wyliczeniowego składającej się z flag bitowych włączono
jedną lub kilka określonych flag. Na przykład dla następującej deklaracji typu wyliczeniowego:
[Flags]
enum language
{
CSharp = 0x0001, VBNET = 0x0002, VB6 = 0x0004, Cpp = 0x0008
}
trzeba sprawdzić, używając logiki Boole a, czy w zmiennej lang zdefiniowanej poniżej włą-
czono flagi Language.CSharp i (lub) Language.Cpp:
Language lang = Language.CSharp | Language.VBNET;
RozwiÄ…zanie
Aby sprawdzić, czy w zmiennej włączono określoną flagę bitową, można wykorzystać nastę-
pujÄ…cÄ… instrukcjÄ™ warunkowÄ…:
if((lang & Language.CSharp) == Language.CSharp)
{
// W zmiennej lang włączono co najmniej wartość Language.CSharp.
}
Aby sprawdzić, czy w zmiennej włączono wyłącznie określoną flagę bitową, można wyko-
rzystać następującą instrukcję warunkową:
if(lang == Language.CSharp)
{
// W zmiennej lang włączono tylko wartość Language.CSharp.
}
Aby sprawdzić, czy w zmiennej włączono zbiór wszystkich flag bitowych, można skorzystać
z następującej instrukcji warunkowej:
if((lang & (Language.CSharp | Language.VBNET)) ==
(Language.CSharp | Language.VBNET))
{
// W zmiennej lang włączono co najmniej elementy Language.CSharp oraz Language.VBNET.
}
Aby sprawdzić, czy w zmiennej włączono jedynie zbiór określonych flag bitowych, można
skorzystać z następującej instrukcji warunkowej:
if((lang | (Language.CSharp | Language.VBNET)) ==
(Language.CSharp | Language.VBNET))
{
// W zmiennej lang włączono jedynie elementy Language.CSharp oraz Language.VBNET.
}
1.21. Sprawdzanie, czy ustawiono jednÄ… czy kilka flag w danych typu wyliczeniowego | 55
Analiza
W przypadku typów wyliczeniowych zdefiniowanych jako flagi bitowe z wykorzystaniem
atrybutu Flags zazwyczaj występuje potrzeba wykonania określonych instrukcji warunkowych.
Zwykle wykorzystuje siÄ™ w nich operatory bitowe AND (&) oraz OR (|).
Sprawdzenie, czy w zmiennej ustawiono określone flagi bitowe, można wykonać za pomocą
następującej instrukcji warunkowej:
if((lang & Language.CSharp) == Language.CSharp)
gdzie lang jest zmiennÄ… typu wyliczeniowego Language.
Operator & w połączeniu z maską bitową wykorzystuje się w celu stwierdzenia, czy określo- [ Pobierz całość w formacie PDF ] - zanotowane.pl
- doc.pisz.pl
- pdf.pisz.pl
- matkadziecka.xlx.pl