Jika saya memiliki variabel yang memegang flag enum, dapatkah saya melakukan iterate pada nilai bit dalam variabel tertentu? Atau apakah saya harus menggunakan Enum.GetValues untuk beralih ke seluruh enum dan memeriksa yang ditetapkan?
c#
enums
enum-flags
Olivier Rogier
sumber
sumber
Jawaban:
sumber
HasFlag
tersedia dari .NET 4 dan seterusnya.Enum.GetValues(input.GetType()).Cast<Enum>().Where(input.HasFlag);
myEnum.GetFLags()
static IEnumerable<Enum> GetFlags(this Enum input)
Berikut ini adalah solusi Linq untuk masalah tersebut.
sumber
.Where(v => !Equals((int)(object)v, 0) && e.HasFlag(v));
jika Anda memiliki nilai nol untuk diwakiliNone
Tidak ada metode builtin untuk mendapatkan setiap komponen sejauh yang saya tahu. Tapi di sini ada satu cara Anda bisa mendapatkannya:
Saya mengadaptasi apa yang
Enum
dilakukan secara internal untuk menghasilkan string sebagai gantinya mengembalikan bendera. Anda dapat melihat kode di reflektor dan harus kurang lebih setara. Bekerja dengan baik untuk kasus penggunaan umum di mana ada nilai yang mengandung banyak bit.Metode ekstensi
GetIndividualFlags()
mendapatkan semua bendera individu untuk suatu jenis. Jadi nilai yang mengandung banyak bit ditinggalkan.sumber
Bar
,Baz
danBoo
bukannya adilBoo
.Boo
(nilai kembali menggunakanToString()
). Saya telah men-tweak untuk memungkinkan hanya bendera individu. Jadi, dalam contoh saya, Anda bisa mendapatkanBar
danBaz
bukannyaBoo
.Kembali pada hal ini beberapa tahun kemudian, dengan pengalaman yang sedikit lebih banyak, jawaban pamungkas saya hanya untuk nilai bit tunggal, bergerak dari bit terendah ke bit tertinggi, adalah sedikit variasi dari rutinitas dalam Jeff Mercado:
Tampaknya berfungsi, dan meskipun saya keberatan beberapa tahun yang lalu, saya menggunakan HasFlag di sini, karena jauh lebih terbaca daripada menggunakan perbandingan bitwise dan perbedaan kecepatan tidak signifikan untuk apa pun yang akan saya lakukan. (Sangat mungkin mereka telah meningkatkan kecepatan HasFlag sejak saat itu, untuk yang saya tahu ... saya belum menguji.)
sumber
yield return bits;
?Keluar dari metode @ Greg, tetapi menambahkan fitur baru dari C # 7.3,
Enum
batasannya:Batasan baru memungkinkan ini menjadi metode ekstensi, tanpa harus melalui
(int)(object)e
, dan saya bisa menggunakanHasFlag
metode dan melemparkan langsung keT
darivalue
.C # 7.3 juga menambahkan kendala untuk untuk delagate dan
unmanaged
.sumber
flags
parameternya menjadi tipe generikT
juga, jika tidak Anda harus secara eksplisit menentukan jenis enum setiap kali Anda menyebutnya.+1 untuk jawaban yang diberikan oleh @ RobinHood70. Saya menemukan bahwa versi umum dari metode ini nyaman bagi saya.
EDIT dan +1 untuk @AustinWBryan untuk membawa C # 7.3 ke dalam ruang solusi.
sumber
Anda tidak perlu mengulang semua nilai. cukup periksa flag spesifik Anda seperti:
atau (seperti pstrjds katakan dalam komentar) Anda dapat memeriksa untuk menggunakannya seperti:
sumber
Apa yang saya lakukan adalah mengubah pendekatan saya, alih-alih mengetik parameter input dari metode sebagai
enum
tipe, saya mengetiknya sebagai array darienum
tipe (MyEnum[] myEnums
), dengan cara ini saya hanya mengulang melalui array dengan pernyataan switch di dalam loop.sumber
Tidak puas dengan jawaban di atas, meskipun itu awal.
Setelah menyatukan beberapa sumber berbeda di sini:
Poster sebelumnya di utas ini SO QnA
Code Proyek Enum Flags Cek Post
Great Enum <T> Utilitas
Saya membuat ini jadi biarkan saya tahu apa yang Anda pikirkan.
Parameter::
bool checkZero
memberitahukannya untuk memungkinkan0
sebagai nilai flag. Secara defaultinput = 0
mengembalikan kosong.bool checkFlags
: mengatakannya untuk memeriksa apakah atributEnum
tersebut didekorasi dengan[Flags]
atribut.PS. Saya tidak punya waktu sekarang untuk mencari tahu
checkCombinators = false
alg yang akan memaksanya untuk mengabaikan nilai enum yang merupakan kombinasi bit.Ini memanfaatkan Enum Class Helper <T> yang ditemukan di sini yang saya perbarui untuk digunakan
yield return
untukGetValues
:Akhirnya, inilah contoh menggunakannya:
sumber
Membangun berdasarkan jawaban Greg di atas, ini juga menangani kasus di mana Anda memiliki nilai 0 di enum Anda, seperti Tidak Ada = 0. Dalam hal ini, seharusnya tidak mengulangi nilai itu.
Adakah yang tahu bagaimana meningkatkan ini lebih jauh sehingga dapat menangani case di mana semua flag di enum diatur dalam cara yang sangat cerdas yang dapat menangani semua tipe enum yang mendasarinya dan case All = ~ 0 dan All = EnumValue1 | EnumValue2 | EnumValue3 | ...
sumber
Anda dapat menggunakan Iterator dari Enum. Mulai dari kode MSDN:
Itu tidak diuji, jadi jika saya membuat kesalahan jangan ragu untuk memanggil saya. (jelas itu bukan masuk kembali.) Anda harus menetapkan nilai sebelumnya, atau memecahnya menjadi fungsi lain yang menggunakan enum.dayflag dan enum.days. Anda mungkin bisa pergi ke suatu tempat dengan garis besar.
sumber
Bisa juga kode berikut:
Ini masuk ke dalam jika hanya ketika nilai enum terkandung pada nilai
sumber
Semua jawaban bekerja dengan baik dengan flag sederhana, Anda mungkin akan mendapatkan masalah ketika flag digabungkan.
mungkin perlu menambahkan cek untuk menguji apakah nilai enum itu sendiri adalah kombinasi. Anda mungkin perlu sesuatu seperti diposting di sini oleh Henk van Boeijen untuk memenuhi kebutuhan Anda (Anda perlu sedikit gulir ke bawah)
sumber
Metode ekstensi menggunakan batasan Enum dan generik baru untuk mencegah pengecoran:
sumber
Anda dapat melakukannya secara langsung dengan mengonversi ke int tetapi Anda akan kehilangan pemeriksaan tipenya. Saya pikir cara terbaik adalah menggunakan sesuatu yang mirip dengan proposisi saya. Itu membuat tipe yang tepat sepanjang jalan. Tidak diperlukan konversi. Itu tidak sempurna karena tinju yang akan menambah sedikit hit dalam kinerja.
Tidak sempurna (tinju), tetapi ia melakukan pekerjaan tanpa peringatan ...
Pemakaian:
sumber