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
}
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.
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.
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
[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.
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
}
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.
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.