Por mi vida, no puedo recordar cómo configurar, eliminar, alternar o probar un poco en un campo de bits. O no estoy seguro o los mezclo porque rara vez los necesito. Por lo tanto, sería bueno tener una "hoja de trucos".
Por ejemplo:
flags = flags | FlagsEnum.Bit4; // Set bit 4.
o
if ((flags & FlagsEnum.Bit4)) == FlagsEnum.Bit4) // Is there a less verbose way?
¿Puede dar ejemplos de todas las demás operaciones comunes, preferiblemente en sintaxis de C # usando una enumeración [Flags]?
Respuestas:
Trabajé un poco más en estas extensiones. Puede encontrar el código aquí.
Escribí algunos métodos de extensión que extienden System.Enum que uso a menudo ... No estoy afirmando que sean a prueba de balas, pero han ayudado ... Comentarios eliminados ...
Luego se usan de la siguiente manera
fuente
HasFlag
métodoEnum
requiere el boxeo.En .NET 4 ahora puede escribir:
fuente
FlagsEnum
es un nombre feo. :)[Flags]
enumeraciones deben tener nombres en plural, por lo que el nombreFlagsEnum
tiene problemas aún más graves que la fealdad.El idioma es usar el operador bit a bit o igual para establecer bits:
Para aclarar un poco, el idioma es usar bit a bit y con negación:
A veces tienes un desplazamiento que identifica tu bit, y luego el modismo es usar estos combinados con desplazamiento a la izquierda:
fuente
@Dibujó
Tenga en cuenta que, excepto en los casos más simples, Enum.HasFlag conlleva una fuerte penalización de rendimiento en comparación con escribir el código manualmente. Considere el siguiente código:
Más de 10 millones de iteraciones, el método de extensión HasFlags toma la friolera de 4793 ms, en comparación con los 27 ms para la implementación bit a bit estándar.
fuente
HasFlag
método implica boxing / unboxing, lo que explica esta diferencia. Pero el costo es tan trivial (0.4 µs) que, a menos que esté en un círculo cerrado, tomaría la llamada declarativa API más legible (y menos probable con errores) cualquier día.Desafortunadamente, las operaciones de enum de bandera incorporadas de .NET son bastante limitadas. La mayoría de las veces los usuarios se quedan con la lógica de operación bit a bit.
En .NET 4,
HasFlag
se agregó el métodoEnum
que ayuda a simplificar el código del usuario, pero desafortunadamente hay muchos problemas con él.HasFlag
no es de tipo seguro ya que acepta cualquier tipo de argumento de valor de enumeración, no solo el tipo de enumeración dado.HasFlag
es ambiguo en cuanto a si verifica si el valor tiene todas o alguna de las banderas proporcionadas por el argumento de valor enum. Es todo por cierto.HasFlag
es bastante lento ya que requiere un boxeo que causa asignaciones y, por lo tanto, más recolecciones de basura.Debido en parte al soporte limitado de .NET para las enums de flag, escribí la biblioteca de OSS Enums.NET que aborda cada uno de estos problemas y hace que el manejo de las enums de flag sea mucho más fácil.
A continuación se presentan algunas de las operaciones que proporciona junto con sus implementaciones equivalentes utilizando solo el marco .NET.
Combinar banderas
.RED
flags | otherFlags
Enums.NET
flags.CombineFlags(otherFlags)
Eliminar banderas
.RED
flags & ~otherFlags
Enums.NET
flags.RemoveFlags(otherFlags)
Banderas Comunes
.RED
flags & otherFlags
Enums.NET
flags.CommonFlags(otherFlags)
Alternar banderas
.RED
flags ^ otherFlags
Enums.NET
flags.ToggleFlags(otherFlags)
Tiene todas las banderas
.NET
(flags & otherFlags) == otherFlags
oflags.HasFlag(otherFlags)
Enums.NET
flags.HasAllFlags(otherFlags)
Tiene banderas
.RED
(flags & otherFlags) != 0
Enums.NET
flags.HasAnyFlags(otherFlags)
Obtener banderas
.RED
Enums.NET
flags.GetFlags()
Estoy tratando de incorporar estas mejoras en .NET Core y quizás eventualmente en el .NET Framework completo. Puedes ver mi propuesta aquí .
fuente
Sintaxis de C ++, suponiendo que el bit 0 es LSB, suponiendo que las banderas no tengan signo largo:
Compruebe si está configurado:
Verificar si no está configurado:
Conjunto:
Claro:
Palanca:
fuente
Para el mejor rendimiento y cero basura, use esto:
fuente
Para probar un bit, haría lo siguiente: (suponiendo que las banderas son un número de 32 bits)
Bit de prueba:
(Si el bit 4 está configurado, entonces es verdadero) Alternar hacia atrás (1 - 0 o 0 - 1): Restablecer el bit 4 a cero:fuente
~0x08
lugar de0xFFFFFFF7
... (la máscara real para 0x8)Esto se inspiró al usar Conjuntos como indexadores en Delphi, cuando:
fuente
Las operaciones de C ++ son: & | ^ ~ (para y, o, xor y operaciones no bit a bit). También son de interés >> y <<, que son operaciones de desplazamiento de bits.
Entonces, para probar si un bit se establece en un indicador, usaría: if (flags & 8) // prueba el bit 4 se ha establecido
fuente