Ce que je veux faire, c'est quelque chose comme ceci: j'ai des énumérations avec des valeurs marquées combinées.
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;
}
}
Alors je pourrais faire:
MyEnum tester = MyEnum.FlagA | MyEnum.FlagB
if( tester.IsSet( MyEnum.FlagA ) )
//act on flag a
Malheureusement, le générique de C # où les contraintes n'ont aucune restriction d'énumération, seulement class et struct. C # ne voit pas les énumérations comme des structures (même s'il s'agit de types valeur), je ne peux donc pas ajouter de types d'extension comme celui-ci.
Quelqu'un connaît-il une solution de contournement?
struct
très bien.Réponses:
EDIT: Ceci est maintenant en ligne dans la version 0.0.0.2 de UnconstrainedMelody.
(Comme demandé sur mon article de blog sur les contraintes d'énumération . J'ai inclus les faits de base ci-dessous pour une réponse autonome.)
La meilleure solution est d'attendre que je l'inclue dans UnconstrainedMelody 1 . Il s'agit d'une bibliothèque qui prend du code C # avec de "fausses" contraintes telles que
et le transforme en
via une étape de post-construction.
Il ne devrait pas être trop difficile à écrire
IsSet
... même si la restauration pour les deux àInt64
base et desUInt64
drapeaux à base pourrait être la partie la plus délicate. (Je sens certaines méthodes d'aide arriver, ce qui me permet essentiellement de traiter toutes les énumérations d'indicateurs comme si elles avaient un type de baseUInt64
.)Quel serait votre comportement si vous appeliez
? Doit-il vérifier que tous les indicateurs spécifiés sont définis? Ce serait mon attente.
J'essaierai de le faire sur le chemin du retour ce soir ... J'espère avoir un éclair rapide sur les méthodes d'énumération utiles pour que la bibliothèque atteigne rapidement une norme utilisable, puis me détendre un peu.
EDIT: Je ne suis pas sûr du
IsSet
nom, au fait. Options:Les pensées sont les bienvenues. Je suis sûr que cela prendra du temps avant que quoi que ce soit ne soit gravé dans la pierre de toute façon
1 ou soumettez-le sous forme de patch, bien sûr ...
la source
colors.HasAny(Colors.Red | Colors.Blue)
ressemble à du code très lisible.=)
where T : System.Enum
. Cela était déjà écrit ailleurs dans le fil; juste pensé que je le répéterais ici.Depuis C # 7.3, il existe désormais un moyen intégré d'ajouter des contraintes d'énumération:
source: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint
la source
Darren, cela fonctionnerait si les types étaient des énumérations spécifiques - pour que les énumérations générales fonctionnent, vous devez les convertir en ints (ou plus probablement en uint) pour faire le calcul booléen:
la source
Convert.ToUInt32
je n'ai trouvé nulle part ailleurs. AFAIK, c'est la seule solution Pre-Net-4 décente qui fonctionne également en VB. BTW, simatchTo
peut avoir plusieurs bits d'indicateur, remplacez-le!= 0
par== Convert.ToUInt32(matchTo)
.Convert.ToUInt32
utilisé avec une énumération utilisera laConvert.ToUInt32(object)
surcharge, ce qui signifie que CLR encapsulera d'abord ces valeurs avant de passer ensuite à laToUInt32
méthode. Dans la plupart des cas, cela n'a pas d'importance, mais il est bon de savoir que vous occuperez le GC plutôt que si vous utilisez quelque chose comme celui-ci pour analyser des millions d'énumérations par seconde.En fait, c'est possible, avec un truc laid. Cependant, il ne peut pas être utilisé pour les méthodes d'extension.
Si vous le souhaitez, vous pouvez donner
Enums<Temp>
un constructeur privé et une classe héritée abstraite imbriquée publique avecTemp
asEnum
, pour empêcher les versions héritées pour les non-enums.la source
Vous pouvez y parvenir en utilisant IL Weaving et ExtraConstraints
Vous permet d'écrire ce code
Ce qui est compilé
la source
À partir de C # 7.3, vous pouvez utiliser la contrainte Enum sur les types génériques:
Si vous souhaitez utiliser une énumération Nullable, vous devez laisser la contrainte de structure orginial:
la source
Cela ne répond pas à la question d'origine, mais il existe maintenant une méthode dans .NET 4 appelée Enum.HasFlag qui fait ce que vous essayez de faire dans votre exemple
la source
flag
. .NET 4.0 a maintenant cinq ans.La façon dont je le fais est de mettre une contrainte de structure, puis de vérifier que T est une énumération à l'exécution. Cela n'élimine pas complètement le problème, mais le réduit quelque peu
la source
En utilisant votre code d'origine, dans la méthode, vous pouvez également utiliser la réflexion pour tester que T est une énumération:
la source
Voici un code que je viens de créer et qui semble fonctionner comme vous le souhaitez sans avoir à faire quoi que ce soit de trop fou. Ce n'est pas limité aux énumérations définies comme Flags, mais il peut toujours y avoir une vérification si nécessaire.
la source
si quelqu'un a besoin d'un IsSet générique (créé hors de la boîte à la volée pourrait être amélioré), et / ou d'une chaîne en conversion à la volée Enum (qui utilise EnumConstraint présentée ci-dessous):
Si quelqu'un a encore besoin d'exemple chaud pour créer la contrainte de codage Enum:
j'espère que cela aide quelqu'un.
la source
Je voulais juste ajouter Enum comme contrainte générique.
Bien que ce ne soit que pour une petite méthode d'aide utilisant
ExtraConstraints
est un peu trop lourde pour moi.J'ai décidé de simplement créer une
struct
contrainte et d'ajouter une vérification à l'exécutionIsEnum
. Pour convertir une variable de T en Enum, je l'ai d'abord convertie en objet.la source