OR'lu numaralandırma için bir öğe nasıl kaldırılır?


181

Benim gibi bir numaralandırma var:

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

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

Mavi rengi değişken renklerden nasıl kaldırabilirim?


2
Küçük not: C # 'da bitsel bir enum, üstündeki [Bayraklar] özelliğini almalıdır.
Nyerguds

@ Nyerguds, neden bu özelliği alması gerektiğini açıklayabilir misiniz?
etan

Hata ayıklama sırasında daha iyi IntelliSense desteği sağlar, çünkü bilinmeyen numaralandırma değerlerini mevcut değerlerin birleşimi olarak tanır.
Nyerguds

1
Ayrıca daha anlamlı bir .ToString()değer sağlar. örneğin RED, BLUE, YELLOWziyade 22.
Sinjai

Yanıtlar:


331

&Buna ~'MAVİ' (tamamlayıcı) ile ihtiyacınız var .

Tamamlayıcı operatörü, verilen veri türü için esasen tüm bitleri tersine çevirir veya 'çevirir'. Bu nedenle, ANDoperatörü ( &) bir değerle (hadi 'X' değerini diyelim) ve bir veya daha fazla set bitinin tamamlayıcısı (bu bitleri Qve tamamlayıcılarını çağıralım ~Q) kullanırsanız, ifade X & ~Q, ayarlanan bitleri siler Qdan Xsonucu ve döner.

Bu nedenle, BLUEbitleri kaldırmak veya temizlemek için aşağıdaki ifadeyi kullanırsınız:

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

Temizlenecek birden fazla biti aşağıdaki gibi de belirleyebilirsiniz:

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

veya dönüşümlü olarak ...

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

Özetlemek gerekirse:

  • X | Q bit (ler) i ayarlar Q
  • X & ~Q bit (ler) i temizler Q
  • ~X içindeki tüm bitleri çevirir / tersine çevirir X

1
bu yüzden daha fazla kaldırmak istersem yapardım: & = ~ Blah.BLUE & ~ Blah.Green?
Blankman

11
Daha İyicolors &= ~( Blah.BLUE | Blah.GREEN );
par

2
nasıl olağandışı, ben sadece 5 gün önce bunu tekrar yapmak nasıl düşünüyordum :) Bu soru gelen kutumda ve voila güncellendi!
Blankman

Mükemmel cevap. Kod örneklerinizde "& =" değil "= &" demek istediğinizi düşünüyorum;)
Dave Jellison

48

Diğer cevaplar doğrudur, ancak özellikle yukarıdakilerden maviyi çıkarmak için şunu yazabilirsiniz:

colors &= ~Blah.BLUE;

9

And not o...............................

Blah.RED | Blah.YELLOW == 
   (Blah.RED | Blah.BLUE | Blah.YELLOW) & ~Blah.BLUE;

7

Bunun benim gibi tökezleyen diğer insanlar için yararlı olabileceğini düşündüm.

== 0 değerine sahip olacak şekilde ayarlayabileceğiniz enum değerlerini nasıl ele aldığınıza dikkat edin (bazen bir numaralandırma için Bilinmeyen veya Boşta durumuna sahip olmak yararlı olabilir). Bu bit manipülasyon işlemlerine güvenirken sorunlara neden olur.

Ayrıca, 2 değerin diğer gücünün kombinasyonları olan enum değerleriniz olduğunda, örneğin

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

Bu durumlarda, bunun gibi bir uzantı yöntemi kullanışlı olabilir:

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

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

    return states & ~state;
}

Ve ayrıca, birleştirilmiş değerleri (biraz da acımasız bir şekilde de olsa) işleyen denk IsSet yöntemi

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;
}

Bana göre daha basit çözüm 0'ı bayrak olarak kullanmaktan kaçınmak. Genellikle gibi bayrak çeteleler kurmak bu . 0 değeri olan bir durum belirtmekten nasıl faydalandığınızı görmüyorum. Sonuçta, asıl mesele Red, Blue, Green, temel değerler yerine programcı dostu isimlerle ( ) ilgilenebilmenizdir , evet?
Sinjai

== 0 değerine sahip bir noneveya unknownveya unsetgirdiye sahip olmak çoğu durumda iyi bir şeydir, çünkü her zaman belirli bir değerin varsayılan küme olduğunu varsayamazsınız, örneğin yalnızca Kırmızı, Mavi ve Yeşil varsa, varsayılan değer (örneğin, enum oluşturulduğunda veya kullanıcı değiştirmediğinde sahip olduğu değer?)
Sverrir Sigmundarson

Unset = 1 1, 2, 4, 8değerine sahip olamaz ve değerleriniz olarak kullanamaz mısınız? Varsayılan bir değere ihtiyacınız varsa, varsayılan kurucular bunun içindir, değil mi? Ben okunabilirliği uğruna mümkün olduğunca açık olarak tutmak ister ve bir enum güvenerek varsayılan olarak default(int)( 0muhtemelen herhangi geliştirici tarafından bilinen bilgiler olmasına rağmen, bir değer verilmediği zaman, zaten benim tadı için çok sinsi olduğunu). Düzenleme: Ah bekleyin, Unset = 0 yapmak bir şey olmasını engeller Unset | Bluemisiniz?
Sinjai

Sen Sinjai düzenleme doğru yolda, unset değeri == 0 tutmak aslında birkaç sorunları çözer. Biri sizin bahsettiğiniz, diğeri ise tüm enum değerlerinin ayarını kaldırırsanız, sıfıra ayarlanmışsa "Unset" için özel bir duruma ihtiyacınız yoktur. (örneğin Red & ~Red, sıfır ile sonuçlanırsanız, bu durumu kontrol etmek ve Unsetdeğeri açıkça atamak için
kodunuz olması gerekir

Anladım. Kendinizi genellikle ayarlanmamış bayraklarla uğraşırken buluyor musunuz?
Sinjai

2

Xor (^) ne olacak?

Kaldırmaya çalıştığınız BAYRAK orada olduğu göz önüne alındığında, işe yarayacak .. değilse, bir & kullanmanız gerekecek.

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;

1

Bayrak enumunu basitleştirmek ve katlardan kaçınarak okumayı daha iyi hale getirmek için bit kaydırma özelliğini kullanabiliriz. ( Enum Bayrakları Üzerine Büyük Tartışmayı Sona Erdirme adlı iyi bir makaleden )

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

ve ayrıca tüm bitleri temizlemek için

private static void ClearAllBits()
{
    colors = colors & ~colors;
}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.