2012-01-21 22 views
32

Sadece bir tane enum bayrağı ayarlanmış olup olmadığını bilmek istiyorum, hangileri değil. Benim şu anki düşüncem, 2'nin gücü olup olmadığını kontrol etmektir. Enum türlerine göre daha iyi bir yol var mı? enum bayrakların açık kombinasyonlarını tanımlamak etmezse değer enum tanımlanması durumundaBirden fazla numara bayrağının ayarlanıp ayarlanmadığını nasıl kontrol ederim?

[Flags] 
enum Foo 
{ 
Flag1 = 0x01, 
Flag2 = 0x02, 
Flag3 = 0x04, 
Flag4 = 0x08, 
Flag5 = 0x10, 
Flag6 = 0x20, 
Flag7 = 0x40, 
Flag8 = 0x80 
} 

private bool ExactlynOneFlagSet(Foo myFoo) 
{ 
    var x = (byte) myFoo; 
    return (x != 0) && ((x & (x - 1)) == 0); //Check if a power of 2 
} 

if(!ExactlynOneFlagSet(Foo myFoo)) 
{ 
    //Do something 
} 
+0

Bu oldukça basit görünüyor, evet. Neden böyle yapmıyorsun? – Groo

+2

Lütfen unvanlarınızı "C#:" ve benzeriyle eklemeyin. Etiketler bunun için var. –

+0

Neden bunun bir soru olarak gizlenmiş bir "çözümüme bakın" sorusu olduğunu hissediyorum ... –

cevap

10
private bool ExatlyOneFlagSet(Foo myFoo) 
{ 
    return !myFoo.ToString().Contains(','); 
} 
+1

@MarkHall in.NET birden fazla bayrak ayarlanmışsa, enum'un dize temsili virgülle ayrılmış bir listedir. –

+1

@MarkHall Flags özniteliği, virgülle ayrılmış ayrı ayrı değer isimlerini göstermesini sağlar. Devam edebilir ve deneyebilirsiniz. – itsme86

+0

Ben –

7

, sadece kontrol edebilirsiniz:

private bool ExactlynOneFlagSet(Foo myFoo) 
{ 
    return Enum.IsDefined(typeof(Foo), myFoo); 
} 
+0

Neden düşüş var? –

+0

+1: Bu, enum açıkça kombinasyonları tanımlasa bile çalışır (enum Foo {Yok = 0, A = 1, B = 2, C = 4, AB = A | B, BC = B | C, Hepsi = A | B | C,} '). Önceden tanımlanmış kombinasyonlardan birini ('Enum.IsDefined (typeo (Foo), Foo.A | Foo.B)') belirtmek “true” değerini verir: aslında tanımlanmış bir değerdir. –

+0

@NicholasCarey, evet, AB için true değerini döndürür, ancak AB'nin birden fazla bit kümesi vardır ... OP, değerin tanımlanmaması durumunda birden fazla bit kümesinin olup olmadığını bilmek ister. –

52

Its bir Bit operasyonu!

if ((myFoo & (myFoo -1)) != 0) //has more than 1 flag 

açıklamada çekleri myFoo değeri ikisinin gücü değilse. Ya da tam tersi, (myFoo & (myFoo -1)) == 0 ifadesi ikisinin gücünü kontrol eder. Fikir şu ki, sadece tek bayrak değerleri ikisinin gücü olacak. Birden fazla bayrak ayarlanması, myFoo'un iki değerinin güçsüz olmasına neden olur.

Bu yanıtta daha fazla bilgi benzer bir soruda bulunabilir: https://stackoverflow.com/a/1662162/2404788. Jacob senin yöntem hiç de doğru olmayan bir açıklama açıklandığı gibi biraz işlemleri hakkında daha fazla bilgi için

http://en.wikipedia.org/wiki/Bitwise_operation

+3

+1, çok zarif bir çözüm! –

+0

@Guido Mükemmel çözüm. Biraz açıklama ekleyebilir misiniz lütfen? – Shimmy

+0

Teşekkürler @Shimmy. Temel bir açıklama ekledim. Umarım yararlıdır –

0

gidin. Şahsen ben, özellikle mantık söz konusu olduğunda, matematiksel olarak programlamadan daima kaçınıyorum. Öyleyse çözümüm, "sayımın bir olduğunu bilmek istiyorsam, sayın ve bir numarayla karşılaştır" gibi bir şey olurdu.

public static bool OneIsSet(Type enumType, byte value) 
    { 
     return Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == 1; 
    } 

    public static bool OneIsSet(Type enumType, int value) 
    { 
     return Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == 1; 
    } 

Ve böyle Foo türü için kullanabilirsiniz: Burada

öyle ben bu yöntemler Genellemelere ve türünü kullanarak daha genel bir şekilde yazılmış olabilir inanıyoruz

var toReturnFalse = (byte)(foo.Flag1 | foo.Flag2); 
    var toReturnTrue = (byte)foo.Flag1; 
    var trueWillBeReturned = OneIsSet(typeof(foo), toReturnTrue); 
    var falseWillBeReturned = OneIsSet(typeof(foo), toReturnFalse); 

taşıma yöntemleri. Ancak int ve bayt olan enumlar için en yaygın taban türleri için yöntemleri dahil ettim. Fakat aynı şeyi kısa ve diğer türler için de yazabilirsiniz. Ayrıca, kodunuzdaki kodu da yalnızca satır içi ekleyebilirsiniz. Sadece bir kod satırı.

Bu yöntemi kullanarak, ayarlanan bayrak sayısının iki veya daha fazla olup olmadığını görebilirsiniz. Ayarlanmış bayrakların sayısı 'n' değerine eşitse, aşağıdaki kod true değerini döndürür.

Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == n; 
İlgili konular