c# enums comparison bit-manipulation bit

c# - Pruebas para valores de bit enumeros



enums comparison (6)

"3.¿Cuál es la forma correcta de manejar el valor" Todos "(en modo bit o lógico). No estoy seguro de si alguna vez recibiríamos un valor donde Todo se combinara con otros tipos de tipo TrainingComponent. No puedo ver por qué lo haríamos, pero "

Parece que no entiendes cómo funcionan los valores de enumeración de bit a bit. ''Todos'' siempre se combina con otros valores, de hecho, es la combinación de todos los valores. Mirando los valores binarios para su enumeración:

Ninguno = 0,
Curso acreditado = 1,
Calificación = 10,
Unidad = 100,
SkillSet = 1000,
UnidadContextualización = 10000,
TrainingPackage = 100000,
Modelo de Curso Acreditado = 1000000,
Todos = 1111111

¿Eso ayuda a tu comprensión?

Realmente no he usado enumeración bitwise antes, y solo quiero asegurarme de que mi prueba sea correcta. Estoy más interesado en probar los valores Ninguno y Todos. Recibimos datos de un servicio web que utiliza esta enumeración para clasificar ciertas partes de los datos. Teniendo en cuenta eso, supongo que ni Ninguno ni Todo se combinarían con ningún otro valor.

Dada la siguiente definición de bit a bit de enumeración

[System.FlagsAttribute()] public enum TrainingComponentTypes : int { None = 0, AccreditedCourse = 1, Qualification = 2, Unit = 4, SkillSet = 8, UnitContextualisation = 16, TrainingPackage = 32, AccreditedCourseModule = 64, All = 127, }

Leí la siguiente cita en este sitio de MSDN sobre FlagAttributes;

Utilice Ninguno como el nombre de la constante enumerada de la bandera cuyo valor es cero. No puede utilizar la constante enumerada Ninguno en una operación AND a nivel de bits para probar un indicador porque el resultado siempre es cero. Sin embargo, puede realizar una comparación lógica, no a nivel de bits, entre el valor numérico y la constante enumerada Ninguna para determinar si se ha establecido algún bit en el valor numérico.

¿Una comparación lógica en este caso se refiere a una prueba de igualdad normal para enumeraciones? Por ejemplo;

TrainingComponentTypes tct = TrainingComponentTypes.None; if (tct == TrainingComponentTypes.None) { ... }

Para una comparación a nivel de bits , estoy realizando lo siguiente;

TrainingComponentTypes tct = TrainingComponentTypes.AccreditedCourse | TrainingComponentTypes.Qualification | TrainingComponentTypes.TrainingPackage; Assert.IsTrue((tct & TrainingComponentTypes.AccreditedCourse) == TrainingComponentTypes.AccreditedCourse, "Expected AccreditedCourse as part the enum"); Assert.IsFalse((tct & TrainingComponentTypes.SkillSet) == TrainingComponentTypes.SkillSet, "Found unexpected SkillSet as part the enum");

Por último, al realizar pruebas para todos, he probado una comparación lógica y una de bit a bit, y ambas devuelven lo mismo. ¿Debo estar usando uno sobre el otro aquí? Por ejemplo;

TrainingComponentTypes tct = TrainingComponentTypes.All; Assert.IsTrue((tct & TrainingComponentTypes.All) == TrainingComponentTypes.All, "Expected All as part the enum"); Assert.IsTrue((tct) == TrainingComponentTypes.All, "Expected All as part the enum"); // The follow also pass the assertion for a value of All Assert.IsTrue((tct & TrainingComponentTypes.Qualification) == TrainingComponentTypes.Qualification, "Expected Qualification as part the enum"); Assert.IsTrue((tct & TrainingComponentTypes.TrainingPackage) == TrainingComponentTypes.TrainingPackage, "Expected TrainingPackage as part the enum");

Así que en resumen, me gustaría saber lo siguiente sobre las enumeraciones de Bitwise;

  1. ¿Mi comprensión de una comparación lógica es correcta dado mi ejemplo anterior?
  2. ¿Es correcta la forma en que estoy realizando una comparación de bits?
  3. ¿Cuál es la forma correcta de manejar el valor "Todos" (bitwise o lógico)? No estoy seguro si alguna vez recibiríamos un valor donde Todo se combinara con otros TrainingComponentTypes. No puedo ver por qué lo haríamos, pero entonces, ¿nunca se sabe?
  4. ¿Estoy en lo cierto al suponer que las declaraciones de cambio básicamente no deberían usarse para enumeración bitwise (dado que ninguna parece ser un caso especial y requiere una comparación lógica)?

Gracias chris


¿Mi comprensión de una comparación lógica es correcta dado mi ejemplo anterior?

Sí, lógico en este contexto significa los operadores de igualdad y desigualdad.

¿Es correcta la forma en que estoy realizando una comparación de bits?

Sí, pero hay una manera más fácil: Enum.HasFlag . Por ejemplo:

tct.HasFlag(TrainingComponentTypes.Qualification)

en lugar de:

(tct & TrainingComponentTypes.Qualification) == TrainingComponentTypes.Qualification

¿Cuál es la forma correcta de manejar el valor "Todos" (bitwise o lógico)? No estoy seguro si alguna vez recibiríamos un valor donde Todo se combinara con otros TrainingComponentTypes. No puedo ver por qué lo haríamos, pero entonces, ¿nunca se sabe?

Creo que es mejor definir All en la enum como el OR a nivel de bits de todas sus partes. Pero verás que la gente lo hace de ambas maneras.

¿Estoy en lo cierto al suponer que las declaraciones de cambio básicamente no deberían usarse para enumeración bitwise (dado que ninguna parece ser un caso especial y requiere una comparación lógica)?

No, en absoluto. Siéntase libre de usarlos es switch instrucciones. Los valores de los case deben ser constantes, pero pueden ser expresiones y se prueban para la igualdad. El compilador te dirá si haces algo tonto como intentar usar el mismo valor de case dos veces.


  1. Sí.

  2. Podrían usarse tanto lógicas como bit a bit. El uso depende de si todos son todos los bits establecidos o solo el OR a nivel de bits de todos los valores que ha definido.

  3. Sí, pero no por None . Un conmutador compara un solo valor, mientras que un campo de bits obviamente puede tener múltiples valores.

Como otros han señalado, Enum contiene Enum.HasFlag .


1 y 2 - sí, sin embargo, hay una manera de hacerlo un poco más fácil de leer:

TrainingComponentTypes tct = TrainingComponentTypes.AccreditedCourse | TrainingComponentTypes.Qualification; Assert.IsTrue(tct.HasFlag(TrainingComponentTypes.AccreditedCourse), "Expected AccreditedCourse as part the enum");

3 - No estoy seguro si necesitas Todo el valor en absoluto. Yo lo eliminaría.

4 - Sí, la instrucción de cambio generalmente no tiene sentido para las enumeraciones de indicadores.


1 y 2 se ven bien

3. Todo como lo tiene definido no se puede combinar con nada sin perder datos. Si "todo" es un valor real que espera recibir del servidor, probablemente debería cambiarlo a 128.

de lo contrario, es un valor de conveniencia que puede usar para probar si se ha establecido algún valor ... no debería necesitarlo a menos que los valores de los indicadores se envíen como datos binarios y se empaqueten en un byte que puede contener otros datos.

4. Se podrían usar las instrucciones de cambio, pero no funcionarán bien si / cuando tiene valores que tienen más de una marca, si hay pequeños subconjuntos de combinaciones de marcas válidas, todavía pueden ser útiles.


Respuesta corta: si :)

Más:

1) Todas las operaciones se realizan en el valor entero de la variable flags, por lo que puede pensar en ellas en términos de esto.

2) si.

3) Cualquiera de las dos funciona. Sin embargo, vale la pena señalar que si alguien mete un valor no válido en una variable, entonces el == TrainingComponentTypes.All versión fallará. Por ejemplo:

var badValue = (TrainingComponentTypes)128 | TrainingComponentTypes.All; // now badValue != TrainingComponentTypes.All // but (badValue & TrainingComponentTypes.All) == TrainingComponentTypes.All

Para esta parte:

No estoy seguro si alguna vez recibiríamos un valor donde Todo se combinara con otros TrainingComponentTypes.

No estoy seguro de que entiendas completamente cómo funciona la enumeración debajo de las portadas.

The value of All is: 127 = 1111111 (binary) The other values are: AccreditedCourse = 0000001 Qualification = 0000010 Unit = 0000100 SkillSet = 0001000 UnitContextualisation = 0010000 TrainingPackage = 0100000 AccreditedCourseModule = 1000000

Como se puede ver, Todo es simplemente a nivel de bits | De todos estos valores juntos. No puedes combinar ningún otro tipo de TraningComponentTypes con All, porque All ya los incluye! Además, si las combinas todas juntas con | usted mismo es exactamente lo mismo que usar Todo directamente (por lo tanto, Todo es simplemente una conveniencia cuando lo define dentro de una enumeración).

4) Podría usarlo para verificar Ninguno o Todos, pero no para otros valores.

Vale la pena señalar que hay un método conveniente en Enum que hará estas comprobaciones por usted: Enum.HasFlag .