¿Por qué los permisos de enumeración a menudo tienen 0, 1, 2, 4 valores?


¿Por qué la gente siempre usa valores de enumeración como 0, 1, 2, 4, 8 y no 0, 1, 2, 3, 4?

Tiene algo que ver con operaciones de bits, etc.?

Realmente apreciaría un pequeño fragmento de muestra sobre cómo se usa correctamente :)

[Flags]
public enum Permissions
{
    None   = 0,
    Read   = 1,
    Write  = 2,
    Delete = 4
}
Author: Peter Mortensen, 0000-00-00

7 answers

Porque son poderes de dos y puedo hacer esto: {[10]]}

var permissions = Permissions.Read | Permissions.Write;

Y quizás más tarde...

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

Es un campo de bits, donde cada bit establecido corresponde a algún permiso (o a lo que corresponda lógicamente el valor enumerado). Si estos se definieran como 1, 2, 3, ... no sería capaz de usar operadores bitwise de esta manera y obtener resultados significativos. Para profundizar...

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

¿Notas un patrón aquí? Ahora si tomamos mi ejemplo original, i. e.,

var permissions = Permissions.Read | Permissions.Write;

Entonces...

permissions == 00000011

¿Ves? Tanto los bits Read como Write están establecidos, y puedo comprobarlo de forma independiente (También observe que el bit Delete es no establecido y, por lo tanto, este valor no transmite permiso para eliminar).

Permite almacenar múltiples banderas en un solo campo de bits.

 261
Author: Ed S.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-21 19:14:47

Si todavía no está claro en las otras respuestas, piénsalo así:

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

Es solo una forma más corta de escribir:

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
} 

Hay ocho posibilidades pero puedes representarlas como combinaciones de solo cuatro miembros. Si hubiera dieciséis posibilidades, entonces podrías representarlas como combinaciones de solo cinco miembros. ¡Si hubiera cuatro mil millones de posibilidades, entonces podrías representarlas como combinaciones de solo 33 miembros! Obviamente, es mucho mejor tener solo 33 miembros, cada uno (excepto cero) una potencia de dos, que tratar de nombrar cuatro mil millones de artículos en una enumeración.

 144
Author: Eric Lippert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-19 11:55:13

Porque estos valores representan ubicaciones de bits únicas en binario:

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

Etc., so

1 | 2 == binary 00000011

EDITAR:

3 == binary 00000011

3 en binario está representado por un valor de 1 tanto en el lugar de las unidades como en el lugar de los dos. En realidad es el mismo que el valor 1 | 2. Así que cuando usted está tratando de utilizar los lugares binarios como banderas para representar algún estado, 3 no suele ser significativo (a menos que haya un valor lógico que en realidad es la combinación de los dos)

Para más aclaración, es posible que desee extender su enumeración de ejemplo de la siguiente manera:

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

Por lo tanto en tengo Permissions.All, también tengo implícitamente Permissions.Read, Permissions.Write, y Permissions.Delete

 36
Author: Chris Shain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-21 19:18:39
[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
}

Creo que escribir así es más fácil de entender y leer, y no es necesario calcularlo.

 9
Author: Dozer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-23 19:42:15

Se utilizan para representar indicadores de bits que permiten combinaciones de valores de enumeración. Creo que es más claro si escribes los valores en notación hexadecimal

[Flags]
public Enum Permissions
{
  None =  0x00,
  Read =  0x01,
  Write = 0x02,
  Delete= 0x04,
  Blah1 = 0x08,
  Blah2 = 0x10
}
 5
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-04 16:44:28

Esto es más bien un comentario, pero como eso no soportaría el formato, solo quería incluir un método que he empleado para configurar enumeraciones de flag:

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

Encuentro este enfoque especialmente útil durante el desarrollo en el caso en el que te gusta mantener tus banderas en orden alfabético. Si determina que necesita agregar un nuevo valor de bandera, puede insertarlo alfabéticamente y el único valor que debe cambiar es el que ahora precede.

Tenga en cuenta, sin embargo, que una vez que una solución se publica en cualquier sistema de producción (especialmente si la enumeración se expone sin un acoplamiento apretado, como a través de un servicio web), entonces es altamente recomendable contra el cambio de cualquier valor existente dentro de la enumeración.

 1
Author: Mike Guthrie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-23 12:19:16

Muchas buenas respuestas a esta just solo diré.. si no le gusta, o no puede comprender fácilmente lo que la sintaxis << está tratando de expresar.. Personalmente prefiero una alternativa (y me atrevo a decir, sencillo enum declaration style) {

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

REGISTRO 513 == 513

Mucho más fácil (por lo menos para mí) de comprender. Alinee los describe describa el resultado que desea, obtenga el resultado que DESEA.. No se necesitan" cálculos".

 1
Author: Alex Gray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-25 13:24:59