Powiedzmy, że mam następujące rzeczy
int susan = 2; //0010
int bob = 4; //0100
int karen = 8; //1000
i przekazuję 10 (8 + 2) jako parametr metody i chcę to zdekodować, aby oznaczało susan i karen
Wiem, że 10 to 1010
ale jak mogę zastosować logikę, aby sprawdzić, czy określony bit jest zaznaczony jako włączony
if (condition_for_karen) // How to quickly check whether effective karen bit is 1
W tej chwili jedyne, o czym myślę, to sprawdzić, czy liczba, którą zdałem, jest
14 // 1110
12 // 1100
10 // 1010
8 // 1000
Kiedy mam większą liczbę rzeczywistych bitów w moim scenariuszu ze świata rzeczywistego, wydaje się to niepraktyczne, jaki jest lepszy sposób użycia maski, aby sprawdzić, czy spełniam warunek tylko dla Karen?
Mogę pomyśleć o przesunięciu w lewo, a następnie przesunięciu w prawo, a potem z powrotem, aby wyczyścić fragmenty inne niż ten, który mnie interesuje, ale to również wydaje się zbyt skomplikowane.
Odpowiedzi:
Tradycyjnym sposobem jest użycie
Flags
atrybutu wenum
:Następnie sprawdź konkretną nazwę w następujący sposób:
Logiczne kombinacje bitowe mogą być trudne do zapamiętania, więc ułatwiam sobie życie dzięki
FlagsHelper
klasie *:Pozwoliłoby mi to przepisać powyższy kod jako:
Uwaga mogłem również dodać
Karen
do zestawu robiąc to:I mógłbym usunąć
Susan
w podobny sposób:* Jak Porges wskazał, równowartość tej
IsSet
metody powyżej istnieje już w .NET 4.0:Enum.HasFlag
.Set
IUnset
metody nie wydają się mieć odpowiedniki, choć; więc nadal powiedziałbym, że ta klasa ma pewne zalety.Uwaga: używanie wyliczeń to tylko konwencjonalny sposób rozwiązania tego problemu. Możesz całkowicie przetłumaczyć cały powyższy kod, aby zamiast tego używał ints i będzie działać równie dobrze.
źródło
(names & Names.Susan) == Names.Susan
, co nie wymaga rozszerzeniaNone
.None
wartości dla wszystkich moich wyliczeń, ponieważ wydaje mi się, że jest to wygodne w wielu scenariuszach.var susanIsIncluded = names.HasFlag(Names.Susan);
Set
metody. Więc powiedziałbym, że metody pomocnicze nie są całkowicie bezwartościowe.)names.HasFlag(Names.Susan)
jest takie,(names & Names.Susan) == Names.Susan
które nie zawsze jest podobne(names & Names.Susan) != Names.None
. Na przykład, jeśli sprawdzisz,names.HasFlag(Names.none)
czynames.HasFlag(Names.Susan|Names.Karen)
Bitowe „i” maskują wszystko z wyjątkiem bitu „reprezentującego” Karen. Jeśli każda osoba jest reprezentowana przez jedną pozycję bitową, możesz sprawdzić wiele osób za pomocą prostego:
źródło
Dołączyłem tutaj przykład, który demonstruje, jak można przechowywać maskę w kolumnie bazy danych jako int i jak można ją później przywrócić:
źródło
Aby połączyć maski bitowe, które chcesz użyć bitowe- lub . W trywialnym przypadku, w którym każda łączona wartość ma dokładnie 1 bit (tak jak w przykładzie), jest to równoważne z dodaniem ich. Jeśli jednak masz nakładające się bity, lub je obsługujesz z wdziękiem.
Aby zdekodować maski bitowe ty i twoją wartość za pomocą maski, na przykład:
źródło
Łatwy sposób:
Aby ustawić flagi, użyj operatora logicznego „lub”
|
:Aby sprawdzić, czy flaga jest uwzględniona, użyj
HasFlag
:źródło
HasFlag()
i[Flags]
nie został podany w innych odpowiedziach.Innym naprawdę dobrym powodem do korzystania z maski bitowej w porównaniu z indywidualnymi wartościami logicznymi jest to, że jako programista internetowy podczas integracji jednej witryny z drugą często musimy wysyłać parametry lub flagi w zapytaniu. Dopóki wszystkie twoje flagi są binarne, znacznie prostsze jest użycie pojedynczej wartości jako maski bitowej niż wysyłanie wielu wartości jako bools. Wiem, że istnieją inne sposoby wysyłania danych (GET, POST itp.), Ale prosty parametr w kwerendzie jest wystarczający przez większość czasu w przypadku elementów niewrażliwych. Spróbuj wysłać 128 wartości bool w zapytaniu, aby komunikować się z witryną zewnętrzną. Daje to również dodatkową możliwość nie przekraczania limitu zapytań dotyczących adresów URL w przeglądarkach
źródło