Od czasu do czasu widzę wyliczenie takie jak:
[Flags]
public enum Options
{
None = 0,
Option1 = 1,
Option2 = 2,
Option3 = 4,
Option4 = 8
}
Nie rozumiem, co dokładnie [Flags]
robi ten atrybut.
Czy ktoś ma dobre wyjaśnienie lub przykład?
CatAndDog = Cat | Dog
(logiczne OR zamiast warunkowe), zakładam?Odpowiedzi:
Tego
[Flags]
atrybutu należy używać, ilekroć element wyliczalny reprezentuje zbiór możliwych wartości, a nie pojedynczą wartość. Takie zbiory są często używane z operatorami bitowymi, na przykład:Zauważ, że
[Flags]
atrybut nie włącza tego sam w sobie - wszystko pozwala na ładną reprezentację za pomocą.ToString()
metody:Należy również zauważyć, że
[Flags]
nie powoduje automatycznie, że wartości wyliczone są potęgami dwóch. Jeśli pominiesz wartości liczbowe, wyliczanie nie będzie działać, jak można oczekiwać w operacjach bitowych, ponieważ domyślnie wartości zaczynają się od 0 i zwiększają.Niepoprawna deklaracja:
Wartości, jeśli zostaną zadeklarowane w ten sposób, będą Żółte = 0, Zielone = 1, Czerwone = 2, Niebieskie = 3. To sprawi, że będzie bezużyteczne jako flagi.
Oto przykład poprawnej deklaracji:
Aby pobrać różne wartości we właściwości, możesz to zrobić:
lub przed .NET 4:
Pod przykryciem
Działa to, ponieważ użyłeś potęgi dwóch w swoim wyliczeniu. Pod okładkami wartości wyliczenia wyglądają następująco w postaci binarnych zer i zer:
Podobnie, po ustawieniu właściwości Dozwolone kolory na Czerwony, Zielony i Niebieski za pomocą binarnego
|
operatora bitowego OR , Dozwolone kolory wyglądają następująco:Więc kiedy odzyskujesz wartość, faktycznie wykonujesz bitowe AND
&
dla wartości:Wartość Brak = 0
A jeśli chodzi o użycie
0
w wyliczeniu, cytowanie z MSDN:Więcej informacji na temat atrybutu flagi i jego wykorzystania można znaleźć w msdn i projektowaniu flag w msdn
źródło
ToString
realizacja Twojego wyliczenia używa flagi, a więc nieEnum.IsDefined
,Enum.Parse
itd Spróbuj usunąć flagi i spojrzeć na skutek MyColor.Yellow | MyColor.Red; bez niego dostajesz „5”, z flagami „żółty, czerwony”. Niektóre inne części frameworka również używają [Flags] (np. XML Serialization).myProperties.AllowedColors = MyColor.Red | MyColor.Green | MyColor.Blue;
. Możesz zrobić:myProperties.AllowedColors = myProperties.AllowedColors ^ MyColor.Blue //myProperties.AllowedColors == MyColor.Red | Mycolor.Green
Możesz także to zrobić
Uważam, że przesuwanie bitów jest łatwiejsze niż pisanie 4,8,16,32 i tak dalej. Nie ma to wpływu na kod, ponieważ wszystko odbywa się w czasie kompilacji
źródło
Third = Second << 1
ZamiastThird = 1 << 2
- zobacz pełniejszy opis poniżej1 << 31 == -2147483648
,1 << 32 == 1
,1 << 33 == 2
i tak dalej. Natomiast jeśli mówimyThirtySecond = 2147483648
o wyliczeniu typu int, kompilator zgłasza błąd.Łącząc odpowiedzi https://stackoverflow.com/a/8462/1037948 (deklaracja poprzez przesunięcie bitów) i https://stackoverflow.com/a/9117/1037948 (używając kombinacji w deklaracji) można raczej przesuwać bitem poprzednie wartości niż przy użyciu liczb. Niekoniecznie polecam, ale tylko wskazuję, że możesz.
Zamiast:
Możesz zadeklarować
Potwierdzanie za pomocą LinqPad:
Prowadzi do:
źródło
Poniżej znajduje się przykład pokazujący deklarację i potencjalne użycie:
źródło
W uzupełnieniu do zaakceptowanej odpowiedzi, w C # 7 flagi enum można zapisać za pomocą literałów binarnych:
Myślę, że ta reprezentacja wyjaśnia, jak flagi działają pod przykryciem .
źródło
0b_0100
I poprosił niedawno o czymś podobnym.
Jeśli używasz flag, możesz dodać metodę wyliczania do wyliczeń, aby ułatwić sprawdzanie zawartych flag (szczegóły w poście)
Pozwala to na:
Następnie możesz zrobić:
Uważam to za łatwiejsze do odczytania niż większość sposobów sprawdzania dołączonych flag.
źródło
HasFlag
metodę wyliczania, dzięki czemu możesz zrobić toopt.HasFlag( PossibleOptions.OptionOne )
bez konieczności pisania własnych rozszerzeńHasFlag
jest to znacznie wolniejsze niż wykonywanie operacji bitowych.@Nidonocu
Aby dodać kolejną flagę do istniejącego zestawu wartości, użyj operatora przypisania LUB.
źródło
Podczas pracy z flagami często deklaruję dodatkowe elementy Brak i Wszystkie. Pomagają sprawdzić, czy ustawione są wszystkie flagi, czy też nie jest ustawiona żadna flaga.
Stosowanie:
Aktualizacja 2019-10:
Od wersji C # 7.0 możesz używać literałów binarnych, których czytanie jest prawdopodobnie bardziej intuicyjne:
źródło
Aby dodać
Mode.Write
:źródło
Jest coś zbyt rozwlekły mi o
if ((x & y) == y)...
konstrukcji, zwłaszcza jeślix
Iy
to zarówno złożone zestawy flag i chcesz tylko wiedzieć, czy istnieje jakikolwiek pokrywają.W takim przypadku wszystko, co naprawdę musisz wiedzieć, to to, czy po maskowaniu bitów jest niezerowa wartość [1] .
Kompilowanie konfiguracji @ andnil ...
źródło
enum
, musimy sprawdzić!= 0
.Flagi pozwalają na użycie maskowania bitów w twoim wyliczeniu. Pozwala to łączyć wartości wyliczeń, zachowując te, które są określone.
źródło
Przepraszamy, jeśli ktoś już zauważył ten scenariusz. Idealny przykład flag, które widzimy w odbiciu. Tak Wiążące flagi ENUM. https://docs.microsoft.com/en-us/dotnet/api/system.reflection.bindingflags?view=netframework-4.8
Stosowanie
źródło