2010-02-26 7 views
1

Je ENUM comme çaC#: Mise clé valeur la plus basse dans Bitwise Enum

[Flags] 
public enum Key 
{ 
    None = 0, 
    A = 1, 
    B = 2, 
    C = 4 
} 

Je donne les résultats suivants

Key k1 = Key.A | Key.B | Key.C; 

Je veux obtenir la clé k1 qui a la valeur la plus faible. Comment puis je faire ça?

Exemple:

Key k1 = Key.A | Key.B | Key.C; // I want a 
Key k2 = Key.B | Key.C; // I want b 
Key k3 = Key.A | Key.C; // I want a 
+4

ceci est votre devoir, n'est-ce pas? – tobsen

+2

En outre, s'il s'agit d'une énumération au niveau du bit, il a besoin d'un attribut Flags et généralement une valeur None = 0, et vous ne marquez pas les drapeaux AND lors de la construction des ensembles, vous les. –

+0

@Gjorgji et @NickLarsen: Je viens de me rendre compte que et de corriger la question, cela n'a de sens que si l'attribut Flags est appliqué. – casperOne

Répondre

6
Keys key = Keys.b | Keys.c; 

var lowest = Enum.GetValues(typeof(Keys)) 
    .Cast<Keys>() 
    .OrderBy(x => x) 
    .FirstOrDefault(x => key.HasFlag(x)); 

Légèrement plus efficace et version .NET 4.0-ish de la méthode LINQ.

0

Si vous avez seulement trois valeurs dans le ENUM probablement le plus rapide et le plus facile est de les vérifier un par un. Pour une solution générale, cependant, vous pouvez essayer de convertir la valeur de k1 en nombre entier, trouver la plus grande puissance de 2 qui le divise et le convertir en valeur enum Keys.

0
  1. Obtenir une liste de toutes les valeurs dans le ENUM
  2. corréler ces valeurs à une sorte de type de données comparables
  3. Comparer toutes les valeurs et garder trace de la plus faible
  4. Convert la plus faible avant le type Enum
4
Keys key = Keys.b | Keys.c; 

var lowest = Enum.GetValues(typeof(Keys)) 
    .OfType<Keys>() 
    .Where(x => (x & key) != 0) 
    .OrderBy(x => x) 
    .DefaultIfEmpty((Keys)0); 

Console.WriteLine(lowest); 
+0

Oh mon dieu, j'adore ça. – jason

+0

Je suppose que vous devriez ajouter quelque chose comme '.DefaultIfEmpty ((Keys) 0)' avant d'abord, donc il ne lance pas une exception si la clé est 0. –

+0

Excellente idée, merci! Terminé. –

12

Vous pouvez utiliser une astuce de bit:

Key key = Key.B | Key.C; 
Key lowest = (Key)((int)key & -(int)key); 
+2

J'aime vraiment ça. Bien joué. –

+2

@David: Personnellement, je pense que c'est presque illisible. C'est une curiosité intéressante mais j'espère que personne ne l'utilise réellement dans le code de production! Je préférerais utiliser l'une des méthodes LINQ. Si quelqu'un utilise cela, j'espère qu'il les commentera au moins avec une explication de ce qu'il fait. –

+1

Oui, il faut un peu pour l'obtenir, mais je peux vous garantir que c'est le plus rapide, et c'est tellement concis. C'est certainement un compromis entre lisibilité et efficacité.Cela dit, je mettrais probablement quelque chose comme ça, et j'oublierais ce que j'ai fait plus tard. Néanmoins, c'est assez cool si vous parlez simplement du facteur de geekiness. –

0

Doit être une implémentation itérative où vous testez des bits. Je ferais quelque chose comme ça.

unsigned int k = (unsigned int) k1; 
int pos = -1; 
while (k) { 
    pos++; 
    if (k & 0x1) break; 
    k >>= 1; 
} 
Keys lowestKey = 0; 
if (pos >= 0) lowestKey = 0x1 << pos; 
0

Le code Envoyé n'a pas de sens: a + b + c ne sont pas préfixés par un type nom, afin qu'ils ne se référer aux noms de ENUM, ils semblent être destinés à se référer à.

De plus, si vous utilisez un AND binaire pour combiner des drapeaux, le résultat contiendra tous les fanions dans tous les paramètres - dans ce cas, aucun.

Questions connexes