Bagaimana cara menghapus item untuk ORum enum?

181

Saya memiliki enum seperti:

public enum Blah
{
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16
}

Blah colors = Blah.RED | Blah.BLUE | Blah.YELLOW;

Bagaimana saya bisa menghapus warna biru dari warna variabel?

Blankman
sumber
2
Catatan kecil: enum bitwise dalam C # harus mendapatkan atribut [Bendera] di atasnya.
Nyerguds
@Nyerguds, dapatkah Anda menjelaskan mengapa itu harus mendapatkan atribut?
ethane
Ini memberikan dukungan IntelliSense yang lebih baik saat debugging, karena ia mengakui nilai enum yang tidak diketahui sebagai kombinasi dari nilai yang ada.
Nyerguds
1
Ini juga memberikan nilai yang lebih bermakna .ToString(). misal RED, BLUE, YELLOWdaripada 22.
Sinjai

Jawaban:

331

Anda harus melakukannya &dengan ~(pelengkap) dari 'BIRU'.

Operator komplemen pada dasarnya membalikkan atau 'membalik' semua bit untuk tipe data yang diberikan. Dengan demikian, jika Anda menggunakan ANDoperator ( &) dengan beberapa nilai (sebut saja nilai itu 'X') dan komplemen dari satu atau lebih bit yang ditetapkan (sebut saja bit Qdan komplemennya ~Q), pernyataan X & ~Qmenghapus semua bit yang ditetapkan dalam Qdari Xdan mengembalikan hasilnya.

Jadi untuk menghapus atau menghapus BLUEbit, Anda menggunakan pernyataan berikut:

colorsWithoutBlue = colors & ~Blah.BLUE
colors &= ~Blah.BLUE // This one removes the bit from 'colors' itself

Anda juga dapat menentukan beberapa bit untuk dihapus, sebagai berikut:

colorsWithoutBlueOrRed = colors & ~(Blah.BLUE | Blah.RED)
colors &= ~(Blah.BLUE | Blah.RED) // This one removes both bits from 'colors' itself

atau secara bergantian ...

colorsWithoutBlueOrRed = colors & ~Blah.BLUE & ~Blah.RED
colors &= ~Blah.BLUE & ~Blah.RED // This one removes both bits from 'colors' itself

Jadi untuk meringkas:

  • X | Q set bit Q
  • X & ~Q membersihkan bit Q
  • ~X membalik / membalikkan semua bit X
Slaks
sumber
1
jadi jika saya ingin menghapus lebih banyak saya hanya akan melakukan: & = ~ Blah.BLUE & ~ Blah.Green?
Blankman
11
Lebih baikcolors &= ~( Blah.BLUE | Blah.GREEN );
par
2
betapa tidak biasa, saya hanya berpikir bagaimana melakukan ini lagi sekitar 5 hari yang lalu :) Pertanyaan ini diperbarui di kotak masuk dan voila saya!
Blankman
Jawaban yang bagus Saya pikir maksud Anda "& =" tidak "= &" dalam sampel kode Anda;)
Dave Jellison
48

Jawaban lainnya benar, tetapi untuk secara khusus menghapus biru dari yang di atas Anda akan menulis:

colors &= ~Blah.BLUE;
par
sumber
9

And not Itu...............................

Blah.RED | Blah.YELLOW == 
   (Blah.RED | Blah.BLUE | Blah.YELLOW) & ~Blah.BLUE;
Daniel A. White
sumber
7

Kupikir ini mungkin berguna untuk orang lain yang tersandung di sini seperti aku.

Berhati-hatilah bagaimana Anda menangani nilai enum apa pun yang mungkin Anda tetapkan untuk memiliki nilai == 0 (kadang-kadang bisa bermanfaat untuk memiliki keadaan Tidak Dikenal atau Menganggur untuk enum). Ini menyebabkan masalah ketika mengandalkan operasi manipulasi bit ini.

Juga ketika Anda memiliki nilai enum yang merupakan kombinasi dari kekuatan lain dari 2 nilai, misalnya

public enum Colour
{
    None = 0,  // default value
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16,
    Orange = 18  // Combined value of RED and YELLOW
}

Dalam kasus ini, metode ekstensi seperti ini mungkin berguna:

public static Colour UnSet(this Colour states, Colour state)
{
    if ((int)states == 0)
        return states;

    if (states == state)
        return Colour.None;

    return states & ~state;
}

Dan juga metode IsSet ekuivalen yang menangani nilai-nilai gabungan (meskipun sedikit cara hacky)

public static bool IsSet(this Colour states, Colour state)
{
    // By default if not OR'd
    if (states == state)
        return true;

    // Combined: One or more bits need to be set
    if( state == Colour.Orange )
        return 0 != (int)(states & state);

    // Non-combined: all bits need to be set
    return (states & state) == state;
}
Sverrir Sigmundarson
sumber
Sepertinya saya bahwa solusi yang lebih sederhana adalah menghindari menggunakan 0 sebagai flag. Saya biasanya mengatur flag enums seperti ini . Saya tidak melihat bagaimana Anda mendapat manfaat dari menetapkan negara dengan nilai 0. Setelah semua, intinya adalah bahwa Anda dapat menyibukkan diri dengan nama ramah-programmer ( Red, Blue, Green) daripada nilai-nilai yang mendasarinya, ya?
Sinjai
Memiliki noneatau unknownatau unsetentri dengan nilai == 0 dalam banyak kasus adalah hal yang baik karena Anda tidak selalu dapat berasumsi bahwa nilai tertentu adalah set default, misalnya jika Anda hanya memiliki Merah, Biru dan Hijau Anda akan memiliki Merah sebagai nilai default (mis. nilai yang dimiliki enum saat dibuat atau pengguna belum memodifikasinya?)
Sverrir Sigmundarson
Tidak bisakah Anda memiliki Unset = 1 dan gunakan 1, 2, 4, 8sebagai nilai Anda? Jika Anda membutuhkan nilai default, itulah gunanya konstruktor default, bukan? Saya suka menjaga hal-hal sejelas mungkin demi keterbacaan, dan mengandalkan enum ke default ke default(int)( 0) ketika tidak diberi nilai, meskipun informasi mungkin diketahui oleh pengembang mana pun, bagaimanapun juga terlalu licik untuk seleraku. Sunting: Oh, tunggu, apakah membuat Unset = 0 mencegah sesuatu menjadi tidak ada Unset | Blue?
Sinjai
Anda berada di jalur yang benar di Sinjai edit, menjaga nilai yang tidak disetel == 0 benar-benar memecahkan beberapa masalah. Satu menjadi apa yang Anda sebutkan dan satu lainnya adalah jika Anda tidak menyetel semua nilai enum maka Anda tidak memerlukan kasus khusus untuk "Tidak disetel" jika disetel ke nol. (mis. jika Anda Red & ~Redkemudian berakhir dengan nol maka Anda harus memiliki kode untuk memeriksa kasus ini dan secara eksplisit menetapkan Unsetnilainya)
Sverrir Sigmundarson
Kena kau. Apakah Anda sering berhadapan dengan bendera yang tidak disetel?
Sinjai
2

Bagaimana dengan xor (^)?

Mengingat bahwa FLAG yang Anda coba hapus ada di sana, itu akan berfungsi .. jika tidak, Anda harus menggunakan &.

public enum Colour
{
    None = 0,  // default value
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16,
    Orange = 18  // Combined value of RED and YELLOW
}

colors = (colors ^ Colour.RED) & colors;
pengguna4509414
sumber
1

Untuk menyederhanakan flag enum dan membuatnya mungkin lebih baik untuk dibaca dengan menghindari kelipatan, kita dapat menggunakan bit shifting. (Dari artikel bagus Mengakhiri Debat Hebat di Bendera Enum )

[FLAG]
Enum Blah
{
   RED = 1,
   BLUE = 1 << 1,
   GREEN = 1 << 2,
   YELLOW = 1 << 3
}

dan juga untuk menghapus semua bit

private static void ClearAllBits()
{
    colors = colors & ~colors;
}
Matt Allen
sumber
0

Anda bisa menggunakan ini:

colors &= ~Blah.RED; 
Gharaei besar
sumber