2016-04-15 10 views
0

Können sagen, ich habe folgendes Enum:Abbildung einer Wert der Enum T auf gültige Flag-Werte (0, 1, 2, 4, 8, 16, 24 ...)

public enum SomeEnum 
{ 
    A, // = 0 
    B, // = 1 
    C, // = 2 
    D, // = 3 
    E, // = 4 
    ... 
} 

Im Grunde, was ich will Zu tun ist, jeden Wert einem gültigen Maskenwert zuzuweisen (0, 1, 2, 4, 8, 16, 32, 64, 128 ...), so dass SomeEnum.A gleich 0 ist, während SomeEnum.B zu 1, SomeEnum.C bis 2, SomeEnum.D bis 4, SomeEnum.E bis 8 und so weiter. Ich habe es irgendwie funktioniert, aber ich stehe vor einem anderen Problem: Je mehr Werte das gegebene Enum hat, desto größer wird dieses Mapping, was wahrscheinlich zu einer Super-Ultra-Riese-Long-Long-Long-Long-Nummer führt. Gibt es dafür bekannte Techniken?

Hier ist mein Code:

public class Flagger<T> where T : struct 
    { 
     private static Dictionary<int, ulong> dictionary = new Dictionary<int, ulong>(); 

     static Flagger() 
     { 
      int indexer = 0; 

      // Since values can be duplicated, we use names instead 
      foreach (String name in Enum.GetNames(typeof(T))) 
      { 
       ulong value = 1UL << indexer++; // 0, 1, 2, 4, 8, 16... 

       Console.WriteLine("{0} generated value {1}", name, value); 

       dictionary.Add(name.GetHashCode(), value); 
      } 
     } 

     private ulong flags; 

     public void Add(T value) 
     { 
      // Create hash only once for both checkup and storation 
      int hash = value.ToString().GetHashCode(); 

      if (Check(hash)) 
      { 
       ulong flag = dictionary[hash]; 

       flags &= flag; 
      } 
     } 

     public void Remove(T value) 
     { 
      // Create hash only once for both checkup and storation 
      int hash = value.ToString().GetHashCode(); 

      if (Check(hash)) 
      { 
       ulong flag = dictionary[hash]; 

       flags &= ~flag; 
      }    
     } 

     /// <summary> 
     /// Tests whether a value has already been added or not 
     /// </summary> 
     public bool Check(T value) 
     { 
      int hash = value.ToString().GetHashCode(); 

      return Check(hash); 
     } 

     /// <summary> 
     /// Quick checkup because no hash needs to be computed 
     /// </summary> 
     private bool Check(int hash) 
     { 
      if (dictionary.ContainsKey(hash)) 
      { 
       ulong flag = dictionary[hash]; 

       return (flags & flag) == flag; 
      } 

      return false; 
     } 
    } 

Der Grund dafür ist alles, was ich mit dem System.Window.Input.Key Enum bin zu arbeiten und ich bin nicht in der Lage, ob einige Flags zu testen freigegeben , zum Beispiel:

Die obige "if" Bedingung gibt mir wahr zurück, was nicht wirklich wahr ist!

+0

Anstatt zu fragen, warum 'Y' nicht zum Erreichen von' X' funktioniert, sollten Sie 'X' erklären, d. H. Was fehlt Ihnen bei 'KeyInterop'? – Aybe

+0

Es sieht so aus, als ob es eine perfekte Antwort auf die gestellte Frage gibt, aber es ist unwahrscheinlich, dass es dir hilft, dein Ziel zu erreichen, egal was es ist. Vielleicht möchten Sie eine neue Frage stellen, die mit dem Ziel beginnt und Ihnen zeigt, was Sie versucht haben zu denken. Umgekehrt führen häufig zu [XY-Problem] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). –

+0

Ich weiß nicht, warum Sie über dieses "XY" Problem sprechen. Ich habe ziemlich genau angegeben, welches X und Y, was ich ausprobiert habe, sowie den Grund, warum mein Ansatz scheitert. Bitte werfen Sie einen Blick auf meine Antworten auf Colin unten. Das sollte hoffentlich einige Dinge klären! –

Antwort

1

Verwenden Bitverschiebung:

[Flags] 
public enum MyEnum 
{ 
    None = 0, 
    First = 1 << 0, 
    Second = 1 << 1, 
    Third = 1 << 2, 
    Fourth = 1 << 3 
} 

EDIT: nach Klärung des Problems, das ist, wie Sie über die Bewertung gehen würden, wenn ein gekennzeichnetes Schlüssel Enum-Wert den Gegenwert eines unterschiedlich typisierte enthält, aber in ähnlicher Weise -name enum Wert.

[Flags] 
public enum Keys1 
{ 
    O = 0, 
    K = 1, 
    A = 1 << 1, 
    Y = 1 << 2 
} 

public enum Keys2 
{ 
    O, 
    K, 
    A, 
    Y 
} 

public bool DoesIncludeKey(Keys1 keys1, Keys2 keys2) 
{ 
    var keys1Names = keys1.ToString().Split(','); 
    return keys1Names.Contains(keys2.ToString()); 
} 

//ToString() on keysVals results in "O,K", 
//which is what makes the above function work. 
var keysVals = Keys1.O | Keys1.K; 

//true! 
var includesK = DoesIncludeKey(keysVals, Keys2.K); 
//false. 
var includesA = DoesIncludeKey(keysVals, Keys2.A); 
+0

Danke für Ihre Zeit. Ich erstelle kein Enum, stattdessen erstelle ich einen Wrapper für ein bestimmtes Enum. Einige Enums haben nicht das Attribut [Flags], und die Werte sind 0, 1, 2, 4, 8, 16 ... Wenn wir mit großen Enums arbeiten, wie das oben angegebene, das 200+ Werte hat hätten wir: 1 << 200 (im statischen Wörterbuch gespeichert), was eine sehr große Zahl ist (viel größer als ulong) und das ist mein Problem. –

+0

Wenn Ihnen die Bits ausgehen, können Sie Bitoperationen (einschließlich AND-ing) nicht wirklich durchführen. AND-inging-Hashes werden jedenfalls keinen Zweck erfüllen. Können Sie das Problem, das Sie lösen möchten, genauer erklären? Ich verstehe, dass Sie einen 'U' Knopf drücken wollen, aber ich verstehe nicht, warum/wie dieser Knopfdruck wie ein markierter Enum kommt. Es könnte sich lohnen, den Ansatz zu überdenken. – Colin

+0

Sie haben jetzt meinen Punkt (nach Ihrer Bearbeitung). Die System.Windows.Input.Key-Enumeration verfügt nicht über das Attribut flags (das tut System.Windows.Forms.Keys jedoch). Der Grund, warum ich gerade keine Gleichheitsoperation mache (=), ist, weil ich es zum Beispiel gegen mehrere andere Schlüssel testen soll (stell dir vor, wir haben eine flaggable enum): Key keystroke = Key.W | Schlüssel; Wenn ich dann prüfen wollte, ob dieser Tastendruck die S-Taste enthält, würde ich das einfach tun: if ((keystroke & Key.S) == Key.S). Es gibt keine Art von Aufzählung, die die virtuellen Schlüsselcodes in sich gegenseitig ausschließende Werte abbildet. –