2010-09-16 14 views
10

Lorsque vous utilisez énumérations avec des champs de bits:Existe-t-il un autre moyen de tester les champs de bits Enum?

enum ReallyBigEnum { FirstChoice = 0x01, AnotherOption = 0x02 } 
    ReallyBigEnum flag = ReallyBigEnum.FirstChoice | ReallyBigEnum.AnotherOption; 

le code utilisé pour tester les bits est:

if((flag & ReallyBigEnum.AnotherOption) == ReallyBigEnum.AnotherOption) { ... } 

qui semble bavard et sujette aux erreurs en raison de la nécessité de répéter le bit testé.

Ce serait bien s'il y avait une façon de dire:

if(flag.IsSet(ReallyBigEnum.AnotherOption)) { ... } 

mais énumérations ne prennent pas en charge les méthodes d'instance. Donc, j'ai essayé une fonction de modèle:

class Enums 
    { 
     public static bool IsSet<T>(T flag, T bit) { return (flag & bit) == bit; } 
    } 

mais le code pour tester les bits ressemble alors à ceci:

if(Enums.IsSet<ReallyBigEnum>(flag, ReallyBigEnum.AnotherOption)) { ... } 

ce qui est beaucoup à écrire. Ensuite, j'ai essayé de le raccourcir:

class Enums 
    { 
     public static bool IsSet(int flag, int bit) { return (flag & bit) == bit; } 
    } 

mais vous devez jeter chaque valeur à son type de base comme celui-ci:

if(Enums.IsSet((int)flag, (int)ReallyBigEnum.AnotherOption)) { ... } 

qui est aussi une douleur au code et perd le bénéfice de la vérification du type .

La même fonction peut être écrite pour utiliser les paramètres 'objet', mais le type d'objet et le type de base sous-jacent doivent être testés. Donc, je suis coincé avec le standard, de manière redondante en haut.

Est-ce que quelqu'un a d'autres idées sur une façon propre et simple de tester les champs de bits Enum?

Merci beaucoup.

Répondre

6

Jusqu'à .Net 3.5 c'est votre seule option. Dans .Net 4.0, il existe une méthode HasFlag sur l'énumération.

+0

La méthode hasFlag() est la solution parfaite, bien sûr. Merci! Malheureusement, notre environnement de développement utilise toujours .NET 2.0. –

2
if((flag & ReallyBigEnum.AnotherOption) != 0) { ... } 

MISE À JOUR:

ci-dessus fonctionne évidemment que si vous testez un seul bit. Si vous voulez tester plusieurs bits, alors un autre élément est requis, selon que vous recherchez tous les bits ou tout bit.

test que tout d'un ensemble de bits est défini

Dans ce cas, il suffit d'utiliser une variante de la version à un seul bit.

if((flag & (ReallyBigEnum.FirstOption | ReallyBigEnum.AnotherOption)) != 0) { ... } 

que tous les tests d'un ensemble de bits est défini

Pour ce cas achive clarté et la fiabilité, je vous suggère de créer une constante qui contient tous les bits.

const int ReallyBigEnum WickedAwesomeOptions = ReallyBigEnum.FirstOption | ReallyBigEnum.AnotherOption; 
... 
if (flag & WickedAwesomeOptions == WickedAwesomeOptions) { ... } 

Une partie de la redondance est toujours là, mais ce n'est pas fragile ou prêtant à confusion, et il est facile à entretenir.

Si la combinaison de bits s'applique largement, vous pouvez l'ajouter à l'énumération elle-même.

[Flags] 
enum ReallyBigEnum 
{ 
    FirstOption = 1, 
    AnotherOption = 2, 
    WickedAwesomeOptions = FirstOption | AnotherOption, 
} 
.... 
if (flag & ReallyBigEnum.WickedAwesomeOptions == ReallyBigEnum.WickedAwesomeOptions) { ... } 
+0

Ceci supprime la redondance mais ne fonctionnera que si tous les drapeaux sont des bits uniques. Les drapeaux composés avec plusieurs bits peuvent renvoyer des faux positifs. –

+0

@Chris C. - Bien sûr, cela ne fonctionne qu'avec des drapeaux à un seul bit. C'est exactement ce que la question demande. Aucune partie de la question ne concerne la vérification de plusieurs bits. –

+0

@Chris C. - J'ai modifié la réponse pour répondre à cette nouvelle question. –

2
/// <summary> 
/// Taken from https://stackoverflow.com/questions/9033/hidden-features-of-c/407325#407325 
/// instead of doing (enum & value) == value you can now use enum.Has(value) 
/// </summary> 
/// <typeparam name="T">Type of enum</typeparam> 
/// <param name="type">The enum value you want to test</param> 
/// <param name="value">Flag Enum Value you're looking for</param> 
/// <returns>True if the type has value bit set</returns> 
public static bool Has<T>(this System.Enum type, T value) 
{ 
    return (((int)(object)type & (int)(object)value) == (int)(object)value); 
} 

Voici une méthode d'extension, je pris du above link

Utilisation:

MyFlagEnum e = MyFlagEnum.First | MyFlagEnum.Second; 
if(e.Has(MyFlagEnum.First)) 
{ 
    // Do stuff 
} 
+0

Oh mais vous utilisez .NET 2, donc pas de méthodes d'extension ... – PostMan

+0

Très bonne solution. La documentation indique que pour C#, les méthodes d'extension sont tout aussi efficaces que les méthodes de classe d'origine. Les méthodes d'extension ont été introduites dans .NET v3.0. Ce code fait une hypothèse sur la taille de l'Enum qui peut être basée sur des entiers longs et non signés. –

+1

Si la conversion a été modifiée en: (long) (objet) valeur cela fonctionnerait-il pour tous les types entiers? –