Digamos que tengo lo siguiente
int susan = 2; //0010
int bob = 4; //0100
int karen = 8; //1000
y paso 10 (8 + 2) como parámetro a un método y quiero decodificar esto para que signifique susan y karen
Yo se que 10 es 1010
pero ¿cómo puedo hacer algo de lógica para ver si un bit específico está marcado como en
if (condition_for_karen) // How to quickly check whether effective karen bit is 1
En este momento, todo lo que puedo pensar es verificar si el número que pasé es
14 // 1110
12 // 1100
10 // 1010
8 // 1000
Cuando tengo una mayor cantidad de bits reales en mi escenario del mundo real, esto parece poco práctico, ¿cuál es una mejor manera de usar una máscara para verificar si cumplo o no con la condición para solo Karen?
Puedo pensar en desplazarme a la izquierda y luego volver a cambiar a la derecha y luego volver a borrar partes distintas de la que me interesa, pero esto también parece demasiado complejo.
Respuestas:
La forma tradicional de hacer esto es usar el
Flags
atributo en unenum
:Luego, buscaría un nombre particular de la siguiente manera:
Las combinaciones lógicas bit a bit pueden ser difíciles de recordar, así que me facilito la vida con una
FlagsHelper
clase *:Esto me permitiría reescribir el código anterior como:
Tenga en cuenta que también podría agregar
Karen
al conjunto haciendo esto:Y podría eliminar
Susan
de manera similar:* Como Porges señaló, un equivalente del
IsSet
método anterior ya existe en .NET 4.0:Enum.HasFlag
. Sin embargo, los métodosSet
yUnset
no parecen tener equivalentes; así que todavía diría que esta clase tiene algún mérito.Nota: El uso de enumeraciones es solo la forma convencional de abordar este problema. Puede traducir totalmente todo el código anterior para usar ints en su lugar y funcionará igual de bien.
fuente
(names & Names.Susan) == Names.Susan
, que no requiere unNone
.None
valor para todas mis enumeraciones, ya que me parece que resulta conveniente en muchos escenarios.var susanIsIncluded = names.HasFlag(Names.Susan);
Set
método. Por lo tanto, diría que los métodos auxiliares no son al menos totalmente inútiles).names.HasFlag(Names.Susan)
es como lo(names & Names.Susan) == Names.Susan
que no siempre es como(names & Names.Susan) != Names.None
. Por ejemplo, sinames.HasFlag(Names.none)
names.HasFlag(Names.Susan|Names.Karen)
El bit a bit "y" ocultará todo excepto el bit que "representa" a Karen. Siempre que cada persona esté representada por una posición de un solo bit, puede verificar a varias personas con un simple:
fuente
He incluido un ejemplo aquí que demuestra cómo podría almacenar la máscara en una columna de la base de datos como un int, y cómo restablecería la máscara más adelante:
fuente
Para combinar máscaras de bits, desea utilizar bit a bit o . En el caso trivial en el que cada valor que combina tiene exactamente 1 bit activado (como su ejemplo), es equivalente a sumarlos. Si ha superpuestas trozos sin embargo, o 'ing ellos maneja el caso con gracia.
Para decodificar las máscaras de bits usted y su valor con una máscara, así:
fuente
Manera fácil:
Para establecer las banderas, use el operador lógico "o"
|
:Y para comprobar si se incluye una bandera, utilice
HasFlag
:fuente
HasFlag()
y[Flags]
.Otra razón realmente buena para usar una máscara de bits frente a bools individuales es que, como desarrollador web, al integrar un sitio web a otro, con frecuencia necesitamos enviar parámetros o indicadores en la cadena de consulta. Siempre que todos sus indicadores sean binarios, es mucho más sencillo usar un solo valor como máscara de bits que enviar múltiples valores como bools. Sé que hay otras formas de enviar datos (GET, POST, etc.), pero un parámetro simple en la cadena de consulta suele ser suficiente para elementos no sensibles. Intente enviar 128 valores bool en una cadena de consulta para comunicarse con un sitio externo. Esto también brinda la capacidad adicional de no sobrepasar el límite de cadenas de consulta de URL en los navegadores.
fuente