Lo que quiero hacer es algo como esto: tengo enumeraciones con valores marcados combinados.
public static class EnumExtension
{
public static bool IsSet<T>( this T input, T matchTo )
where T:enum //the constraint I want that doesn't exist in C#3
{
return (input & matchTo) != 0;
}
}
Entonces podría hacer:
MyEnum tester = MyEnum.FlagA | MyEnum.FlagB
if( tester.IsSet( MyEnum.FlagA ) )
//act on flag a
Desafortunadamente, C # es genérico donde las restricciones no tienen restricción de enumeración, solo clase y estructura. C # no ve las enumeraciones como estructuras (aunque son tipos de valor), por lo que no puedo agregar tipos de extensión como este.
¿Alguien sabe una solución?
struct
muy bien.Respuestas:
EDITAR: Esto ahora está disponible en la versión 0.0.0.2 de UnconstrainedMelody.
(Como se solicitó en la publicación de mi blog sobre las restricciones de enumeración . He incluido los datos básicos a continuación en aras de una respuesta independiente).
La mejor solución es esperar a que lo incluya en UnconstrainedMelody 1 . Esta es una biblioteca que toma código C # con restricciones "falsas" como
y lo convierte en
a través de un paso posterior a la construcción.
No debería ser demasiado difícil de escribir
IsSet
... aunque atender tanto a las banderasInt64
basadas como a lasUInt64
basadas en banderas podría ser la parte complicada. (Huelo algunos métodos de ayuda que se acercan, básicamente me permiten tratar cualquier enumeración de banderas como si tuviera un tipo base deUInt64
).¿Cuál le gustaría que fuera el comportamiento si llamara
? ¿Debería comprobar que todas las banderas especificadas están configuradas? Esa sería mi expectativa.
Trataré de hacer esto en el camino a casa esta noche ... Espero tener un bombardeo rápido sobre métodos de enumeración útiles para que la biblioteca alcance un estándar utilizable rápidamente, luego relajarme un poco.
EDITAR: No estoy seguro
IsSet
como nombre, por cierto. Opciones:Los pensamientos son bienvenidos. Estoy seguro de que pasará un tiempo antes de que algo quede grabado en piedra de todos modos ...
1 o enviarlo como parche, por supuesto ...
fuente
colors.HasAny(Colors.Red | Colors.Blue)
parece un código muy legible.=)
where T : System.Enum
. Esto ya estaba escrito en otra parte del hilo; solo pensé que lo repetiría aquí.A partir de C # 7.3, ahora hay una forma integrada de agregar restricciones de enumeración:
fuente: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint
fuente
Darren, eso funcionaría si los tipos fueran enumeraciones específicas; para que las enumeraciones generales funcionen, debe convertirlas en ints (o más probablemente uint) para hacer las matemáticas booleanas:
fuente
Convert.ToUInt32
no encontré en ningún otro lugar. AFAIK, es la única solución Pre-Net-4 decente que también funciona en VB. Por cierto, simatchTo
puede tener varios bits de bandera, reemplácelos!= 0
con== Convert.ToUInt32(matchTo)
.Convert.ToUInt32
usado con una enumeración usará laConvert.ToUInt32(object)
sobrecarga, lo que significa que CLR primero encuadrará estos valores antes de pasarlos alToUInt32
método. En la mayoría de los casos, esto no importará, pero es bueno saber que mantendrá el GC bastante ocupado si usa algo como esto para analizar millones de enumeraciones por segundo.De hecho, es posible, con un truco feo. Sin embargo, no se puede utilizar para métodos de extensión.
Si lo desea, puede dar
Enums<Temp>
un constructor privado y una clase heredada abstracta anidada pública conTemp
asEnum
, para evitar versiones heredadas para no enumerados.fuente
Puede lograr esto usando IL Weaving y ExtraConstraints
Te permite escribir este código
Que se compila
fuente
A partir de C # 7.3, puede usar la restricción Enum en tipos genéricos:
Si desea utilizar una enumeración que acepta valores NULL, debe dejar la restricción de estructura original:
fuente
Esto no responde a la pregunta original, pero ahora hay un método en .NET 4 llamado Enum.HasFlag que hace lo que está tratando de hacer en su ejemplo
fuente
flag
. .NET 4.0 ya tiene cinco años.La forma en que lo hago es poner una restricción de estructura, luego verificar que T es una enumeración en tiempo de ejecución. Esto no elimina el problema por completo, pero lo reduce un poco.
fuente
Usando su código original, dentro del método también puede usar la reflexión para probar que T es una enumeración:
fuente
Aquí hay un código que acabo de hacer y que parece funcionar como quieres sin tener que hacer nada demasiado loco. No está restringido solo a enumeraciones configuradas como banderas, pero siempre puede haber una marca de verificación si es necesario.
fuente
si alguien necesita IsSet genérico (creado fuera de la caja sobre la marcha podría mejorarse), yo cadena a la conversión de Enum onfly (que usa EnumConstraint que se presenta a continuación):
Si alguien todavía necesita un ejemplo caliente para crear una restricción de codificación Enum:
Espero que esto ayude a alguien.
fuente
Solo quería agregar Enum como una restricción genérica.
Si bien esto es solo para un pequeño método auxiliar que usa
ExtraConstraints
es demasiado para mí.Decidí simplemente crear una
struct
restricción y agregar una verificación de tiempo de ejecución paraIsEnum
. Para convertir una variable de T a Enum, primero la lanzo al objeto.fuente