example español enum define c# bit-manipulation enum-flags

español - enum definition c#



Banderas enum y operaciones bit a bit vs. "cadena de bits" (6)

Un compañero desarrollador sugirió que almacenemos una selección de días de la semana como una cadena de 7 caracteres de 1 y 0, es decir, "1000100" para el lunes y el viernes. Preferí (y sugerí fuertemente) una solución con Flags enum y operaciones bit a bit, creo que es una forma más limpia de hacerlo, y debería ser más fácil de entender para otros desarrolladores.

[Flags()] public enum Weekdays : int { Monday = 1, Tuesday = 2, Wednesday = 4, Thursday = 8, Friday = 16, Saturday = 32, Sunday = 64 }

Sin embargo, cuando comencé a implementar una solución de muestra, me di cuenta de que tal vez el simple enfoque de la secuencia era más sencillo: ciertamente la cadena de bits es más obvia que "17" si solo estás mirando los datos. Y encuentro que las operaciones bit a bit de C # son contraintuitivas y extremadamente detalladas:

Weekdays workDays = Weekdays.Monday | Weekdays.Tuesday; if ((workDays & Weekdays.Monday) == Weekdays.Monday) {...}

Por supuesto, esto podría envolverse muy bien en los métodos de extensión, pero de repente terminamos con al menos el mismo número de líneas de código que con la solución de cadena, y no puedo argumentar que el código bitwise sea más fácil de leer.

Dicho esto, todavía iría con una enumeración de banderas y operaciones bit a bit. Los beneficios clave que puedo pensar son

  • Mejor interpretación
  • Se necesita menos espacio para el almacenamiento

Entonces, ¿cómo vendo la solución bitwise a mis colegas? ¿Debería? ¿Cuáles son los otros beneficios de usar este método sobre cadenas? Después de completar el proyecto de muestra, descubrí que el equipo aún optó por la solución basada en cadenas. Necesito algunos argumentos mejores / más fuertes. ¿Por qué debería usar las enumeraciones de Flags en lugar de simples cadenas de bits?


De manera divertida, ambos métodos son exactamente lo mismo; solo el método de banderas es más obvio.

Yo personalmente iría con las banderas (aunque, potencialmente, dependiendo de su modelo, sería mejor simplemente almacenar la lista como una lista contra quienquiera que la tenga).

- Editar

Y para ser claro, el rendimiento realmente no necesita ser una consideración para lo que estás haciendo, creo. Así que solo ve con el más legible. (Que, en mi humilde opinión, son las banderas con nombre).


El método Flags es idiomático (es decir, es lo que los programadores experimentados hacen y están acostumbrados a ver y hacer, al menos en los lenguajes C / C ++ / C #).


Haga una clase que pueda contener la combinación de los días de la semana. Dentro de la clase puede representar los datos de cualquier manera, pero definitivamente iría por una enumeración de banderas en lugar de una cadena. Fuera de la clase solo usas los valores enum, y la lógica real está encapsulada en la clase.

Algo como:

[Flags] public enum Days { Monday = 1, Tuesday = 2, Wednesday = 4, Thursday = 8, Friday = 16, Saturday = 32, Sunday = 64, MondayToFriday = 31, All = 127, None = 0 } public class Weekdays { private Days _days; public Weekdays(params Days[] daysInput) { _days = Days.None; foreach (Days d in daysInput) { _days |= d; } } public bool Contains(Days daysMask) { return (_days & daysMask) == daysMask; } public bool Contains(params Days[] daysMasks) { Days mask = Days.None; foreach (Days d in daysMasks) { mask |= d; } return (_days & mask) == mask; } }

Ejemplo de uso:

Weekdays workdays = new Weekdays(Days.MondayToFriday); if (workdays.Contains(Days.Monday, Days.Wednesday)) { ... }


La pregunta debe centrarse en si los ojos humanos alguna vez verán este valor almacenado. Si es así, un formato algo legible por los humanos es obviamente importante (aunque si ese es el caso, yo presentaría un argumento para algo aún más grande, como una serie de nombres de días reales).

Sin embargo, al menos en todas las aplicaciones que he creado, este tipo de información va a un pequeño campo en algún lugar y nunca se vuelve a ver, excepto a través del código c #, lo que significa bitflags son definitivamente los más simples, son los más humanos. legible en código . Sus colegas realmente quieren escribir un analizador de cadenas que asigne los valores 0 y 1 a los valores en lugar de usar la idea incorporada y utilizada durante más de 40 años de las operaciones bit a bit.


No debe crear estructuras de datos no estándar para reemplazar una estructura de datos estándar (en este caso, la enumeración integrada de DayOfWeek). En cambio, amplíe la estructura existente. Esto funciona esencialmente de la misma manera que el método de indicadores de bit del que hablabas.

namespace ExtensionMethods { public static class Extensions { /* * Since this is marked const, the actual calculation part will happen at * compile time rather than at runtime. This gives you some code clarity * without a performance penalty. */ private const uint weekdayBitMask = 1 << Monday | 1 << Tuesday | 1 << Wednesday | 1 << Thursday | 1 << Friday; public static bool isWeekday(this DayOfWeek dayOfWeek) { return 1 << dayOfWeek & weekdayBitMask > 0; } } }

Ahora puedes hacer lo siguiente:

Thursday.isWeekday(); // true Saturday.isWeekday(); // false


Beneficios de usar Flags enum:

Negativos de usar Flags enum:

  • Representación de datos para humanos difíciles de entender (por ejemplo, ¿qué banderas se establecen para 17?)


Beneficios de usar una cadena de bits:

  • Fácil para los programadores para ver qué bits se establecen en una cadena

Negativos de usar una cadena de bits:

  • Enfoque no estándar
  • Más difícil de entender para los programadores que no están familiarizados con su diseño
  • Posiblemente sea más fácil establecer los valores de "basura" (por ejemplo, stringValue = "Sunday")
  • Creación innecesaria de cuerdas
  • Análisis de cadenas innecesarias
  • Trabajo de desarrollo adicional
  • Reinventando la rueda (pero ni siquiera una rueda redonda)


¿Qué tan importante es realmente poder ver la cadena de bits para ver qué se establece? Si es difícil saber que 17 es lunes y viernes, siempre puede usar la calculadora y convertir a binario. O agregue algún tipo de representación de cadena para el uso de "visualización" (o depuración). No es tan difícil.


También me parece que si vas a hacer que la cadena de bits se aproxime sólida, necesitarás encapsular un poco para llevarlo a un nivel de abstracción que el enunciado de Flags ya proporciona. Si el enfoque es simplemente manipular la cadena de bits directamente, entonces será difícil de leer (y comprender) y probablemente sea propenso a errores.

por ejemplo, puede terminar viendo esto:

days = "1000101"; // fixed bug where days were incorrectly set to "1010001"