De vez en cuando veo una enumeración como la siguiente:
[Flags]
public enum Options
{
None = 0,
Option1 = 1,
Option2 = 2,
Option3 = 4,
Option4 = 8
}
No entiendo qué hace exactamente el [Flags]
atributo.
¿Alguien tiene una buena explicación o ejemplo que podrían publicar?
CatAndDog = Cat | Dog
(el OR lógico en lugar del Condicional), supongo?Respuestas:
El
[Flags]
atributo debe usarse siempre que el enumerable represente una colección de valores posibles, en lugar de un solo valor. Tales colecciones a menudo se usan con operadores bit a bit, por ejemplo:Tenga en cuenta que el
[Flags]
atributo no habilita esto por sí mismo; todo lo que hace es permitir una buena representación por el.ToString()
método:También es importante tener en cuenta que
[Flags]
no hace automáticamente que los valores de enumeración sean potencias de dos. Si omite los valores numéricos, la enumeración no funcionará como cabría esperar en las operaciones bit a bit, ya que de forma predeterminada los valores comienzan con 0 y se incrementan.Declaración incorrecta
Los valores, si se declaran de esta manera, serán Amarillo = 0, Verde = 1, Rojo = 2, Azul = 3. Esto lo hará inútil como banderas.
Aquí hay un ejemplo de una declaración correcta:
Para recuperar los valores distintos en su propiedad, uno puede hacer esto:
o antes de .NET 4:
Debajo de las sábanas
Esto funciona porque usaste poderes de dos en tu enumeración. Debajo de las cubiertas, sus valores de enumeración se ven así en binarios y ceros:
Del mismo modo, después de haber configurado su propiedad AllowColors en Rojo, Verde y Azul utilizando el
|
operador OR binario a nivel de bit , AllowColors se ve así:Entonces, cuando recupera el valor, en realidad está realizando bit a bit Y
&
en los valores:El valor Ninguno = 0
Y con respecto al uso de
0
en su enumeración, citando de MSDN:Puede encontrar más información sobre el atributo flags y su uso en msdn y diseñar banderas en msdn
fuente
ToString
implementación de su enumeración utiliza Banderas, y lo mismo ocurreEnum.IsDefined
,Enum.Parse
, etc. Trate de eliminar Banderas y observe el resultado de MyColor.Yellow | MyColor.Red; sin él obtienes "5", con Banderas obtienes "Amarillo, Rojo". Algunas otras partes del marco también usan [Banderas] (por ejemplo, serialización XML).myProperties.AllowedColors = MyColor.Red | MyColor.Green | MyColor.Blue;
. Puedes hacer:myProperties.AllowedColors = myProperties.AllowedColors ^ MyColor.Blue //myProperties.AllowedColors == MyColor.Red | Mycolor.Green
También puedes hacer esto
Encuentro el cambio de bits más fácil que escribir 4,8,16,32 y así sucesivamente. No tiene impacto en su código porque todo se hace en tiempo de compilación
fuente
Third = Second << 1
lugar deThird = 1 << 2
- vea una descripción más completa a continuación1 << 31 == -2147483648
,1 << 32 == 1
,1 << 33 == 2
, y así sucesivamente. Por el contrario, si diceThirtySecond = 2147483648
para un tipo de enumeración int, el compilador arroja un error.Combinando las respuestas https://stackoverflow.com/a/8462/1037948 (declaración mediante bit-shifting) y https://stackoverflow.com/a/9117/1037948 (usando combinaciones en la declaración) puede cambiar bit en lugar de los valores anteriores que usar números. No necesariamente lo recomiendo, sino solo señalar que puedes.
Más bien que:
Puedes declarar
Confirmando con LinqPad:
Resultados en:
fuente
Consulte lo siguiente para ver un ejemplo que muestra la declaración y el uso potencial:
fuente
En extensión a la respuesta aceptada, en C # 7 los indicadores de enumeración se pueden escribir utilizando literales binarios:
Creo que esta representación deja en claro cómo funcionan las banderas debajo de las cubiertas .
fuente
0b_0100
Me preguntó recientemente sobre algo similar.
Si usa banderas, puede agregar un método de extensión a las enumeraciones para facilitar la verificación de las banderas contenidas (consulte la publicación para más detalles)
Esto te permite hacer:
Entonces puedes hacer:
Encuentro esto más fácil de leer que la mayoría de las formas de verificar las banderas incluidas.
fuente
HasFlag
método a las enumeraciones, para que pueda hacerloopt.HasFlag( PossibleOptions.OptionOne )
sin tener que escribir sus propias extensionesHasFlag
es mucho más lento que hacer operaciones bit a bit.@Nidonocu
Para agregar otro indicador a un conjunto de valores existente, use el operador de asignación OR.
fuente
Cuando trabajo con banderas, a menudo declaro Ninguno y Todos los elementos adicionales. Estos son útiles para verificar si todas las banderas están configuradas o no.
Uso:
Actualización 2019-10:
Desde C # 7.0 puede usar literales binarios, que probablemente sean más intuitivos de leer:
fuente
Para agregar
Mode.Write
:fuente
Hay algo demasiado detallado para mí acerca de la
if ((x & y) == y)...
construcción, especialmente six
ANDy
son conjuntos compuestos de banderas y solo desea saber si hay alguna superposición.En este caso, todo lo que realmente necesita saber es si hay un valor distinto de cero [1] después de haber enmascarado .
Partiendo de la configuración de @ andnil ...
fuente
enum
, tendríamos que verificarlo!= 0
.Las banderas le permiten usar bitmasking dentro de su enumeración. Esto le permite combinar valores de enumeración, mientras conserva cuáles se especifican.
fuente
Disculpas si alguien ya notó este escenario. Un ejemplo perfecto de banderas que podemos ver en la reflexión. Sí Banderas vinculantes ENUM. https://docs.microsoft.com/en-us/dotnet/api/system.reflection.bindingflags?view=netframework-4.8
Uso
fuente