web-dev-qa-db-fra.com

Pourquoi les autorisations d'énumération ont-elles souvent des valeurs 0, 1, 2, 4?

Pourquoi les gens utilisent-ils toujours des valeurs d'énumération comme 0, 1, 2, 4, 8 et pas 0, 1, 2, 3, 4?

Cela a-t-il quelque chose à voir avec les opérations sur les bits, etc.?

J'apprécierais vraiment un petit extrait d'extrait sur la façon dont cela est utilisé correctement :)

[Flags]
public enum Permissions
{
    None   = 0,
    Read   = 1,
    Write  = 2,
    Delete = 4
}
157
Pascal

Parce que ce sont des pouvoirs de deux et je peux le faire:

var permissions = Permissions.Read | Permissions.Write;

Et peut-être plus tard ...

if( (permissions & Permissions.Write) == Permissions.Write )
{
    // we have write access
}

Il s'agit d'un champ de bits, où chaque bit défini correspond à une autorisation (ou à ce à quoi la valeur énumérée correspond logiquement). Si ceux-ci étaient définis comme 1, 2, 3, ... vous ne seriez pas en mesure d'utiliser des opérateurs au niveau du bit de cette façon et d'obtenir des résultats significatifs. Pour approfondir ...

Permissions.Read   == 1 == 00000001
Permissions.Write  == 2 == 00000010
Permissions.Delete == 4 == 00000100

Vous remarquez un motif ici? Maintenant, si nous prenons mon exemple d'origine, c'est-à-dire,

var permissions = Permissions.Read | Permissions.Write;

Ensuite...

permissions == 00000011

Voir? Les bits Read et Write sont tous deux définis, et je peux le vérifier indépendamment (Notez également que le bit Delete est pas défini et donc ce la valeur ne transmet pas la permission de supprimer).

Il permet de stocker plusieurs drapeaux dans un seul champ de bits.

265
Ed S.

Si ce n'est toujours pas clair à partir des autres réponses, pensez-y comme ceci:

[Flags] 
public enum Permissions 
{   
   None = 0,   
   Read = 1,     
   Write = 2,   
   Delete = 4 
} 

est juste une façon plus courte d'écrire:

public enum Permissions 
{   
    DeleteNoWriteNoReadNo = 0,   // None
    DeleteNoWriteNoReadYes = 1,  // Read
    DeleteNoWriteYesReadNo = 2,  // Write
    DeleteNoWriteYesReadYes = 3, // Read + Write
    DeleteYesWriteNoReadNo = 4,   // Delete
    DeleteYesWriteNoReadYes = 5,  // Read + Delete
    DeleteYesWriteYesReadNo = 6,  // Write + Delete
    DeleteYesWriteYesReadYes = 7, // Read + Write + Delete
} 

Il y a huit possibilités mais vous pouvez les représenter comme des combinaisons de seulement quatre membres. S'il y avait seize possibilités, vous pourriez les représenter comme des combinaisons de cinq membres seulement. S'il y avait quatre milliards de possibilités, vous pourriez les représenter comme des combinaisons de seulement 33 membres! Il est évidemment bien préférable de n'avoir que 33 membres, chacun (sauf zéro) un pouvoir de deux, que d'essayer de nommer quatre milliards d'articles dans une énumération.

144
Eric Lippert

Parce que ces valeurs représentent des emplacements de bits uniques en binaire:

1 == binary 00000001
2 == binary 00000010
4 == binary 00000100

etc., donc

1 | 2 == binary 00000011

MODIFIER:

3 == binary 00000011

3 en binaire est représenté par une valeur de 1 à la fois à la place des uns et à la place des deux. C'est en fait la même chose que la valeur 1 | 2. Donc, lorsque vous essayez d'utiliser les espaces binaires comme indicateurs pour représenter un état, 3 n'est généralement pas significatif (sauf s'il existe une valeur logique qui est en fait la combinaison des deux)

Pour plus de précisions, vous souhaiterez peut-être étendre votre exemple d'énumération comme suit:

[Flags]
public Enum Permissions
{
  None = 0,   // Binary 0000000
  Read = 1,   // Binary 0000001
  Write = 2,  // Binary 0000010
  Delete = 4, // Binary 0000100
  All = 7,    // Binary 0000111
}

Par conséquent, j'ai Permissions.All, J'ai aussi implicitement Permissions.Read, Permissions.Write, et Permissions.Delete

36
Chris Shain
[Flags]
public Enum Permissions
{
    None   =    0; //0000000
    Read   =    1; //0000001
    Write  = 1<<1; //0000010
    Delete = 1<<2; //0000100
    Blah1  = 1<<3; //0001000
    Blah2  = 1<<4; //0010000
}

Je pense que l'écriture comme celle-ci est plus facile à comprendre et à lire, et vous n'avez pas besoin de la calculer.

9
Dozer

Ils sont utilisés pour représenter les drapeaux de bits qui permettent des combinaisons de valeurs d'énumération. Je pense que c'est plus clair si vous écrivez les valeurs en notation hexadécimale

[Flags]
public Enum Permissions
{
  None =  0x00,
  Read =  0x01,
  Write = 0x02,
  Delete= 0x04,
  Blah1 = 0x08,
  Blah2 = 0x10
}
5
JaredPar

C'est vraiment plus un commentaire, mais comme cela ne prendrait pas en charge le formatage, je voulais simplement inclure une méthode que j'ai utilisée pour configurer les énumérations d'indicateurs:

[Flags]
public enum FlagTest
{
    None = 0,
    Read = 1,
    Write = Read * 2,
    Delete = Write * 2,
    ReadWrite = Read|Write
}

Je trouve cette approche particulièrement utile lors du développement dans le cas où vous souhaitez conserver vos drapeaux par ordre alphabétique. Si vous déterminez que vous devez ajouter une nouvelle valeur d'indicateur, vous pouvez simplement l'insérer par ordre alphabétique et la seule valeur que vous devez modifier est celle qu'elle précède maintenant.

Notez, cependant, qu'une fois qu'une solution est publiée sur n'importe quel système de production (en particulier si l'énumération est exposée sans couplage étroit, comme sur un service Web), il est fortement déconseillé de modifier toute valeur existante au sein de l'énumération.

1
Mike Guthrie

Beaucoup de bonnes réponses à celle-ci… Je vais juste dire .. si vous n'aimez pas, ou ne peut pas facilement comprendre ce que le << la syntaxe essaie d'exprimer .. Personnellement, je préfère une alternative (et j'ose dire, simple enum style de déclaration)…

typedef NS_OPTIONS(NSUInteger, Align) {
    AlignLeft         = 00000001,
    AlignRight        = 00000010,
    AlignTop          = 00000100,
    AlignBottom       = 00001000,
    AlignTopLeft      = 00000101,
    AlignTopRight     = 00000110,
    AlignBottomLeft   = 00001001,
    AlignBottomRight  = 00001010
};

NSLog(@"%ld == %ld", AlignLeft | AlignBottom, AlignBottomLeft);

LOG 513 == 513

Tellement plus facile (pour moi, au moins) à comprendre. Alignez ceux… décrivez le résultat que vous désirez, obtenez le résultat que vous VOULEZ. Aucun "calcul" nécessaire.

1
Alex Gray