2016-09-27 4 views
0

Verstehe ich grundsätzlich falsch, wie HasFlags funktioniert? Ich kann nicht verstehen, warum dieser Code versagt.Warum schlägt meine [Flag] -Enum-Validierung fehl?

Dieser Code nimmt einen Wert und bestimmt, ob es eine gültige Kombination von Werten meiner Enum ist.

Zwei Untergruppen von Enum-Werten werden durch ODER-Verknüpfung anderer Elemente identifiziert: JustTheMonths und Exclusives. JustTheMonths ist in der Enum deklariert, und Exclusives ist in der Validierungsmethode enthalten.

Wenn ich 1 oder 2 (Nicht zugeordnet oder Unbekannt) an diese Methode übergebe, identifiziert sie sie korrekt als gültig - Exclusives, aber nicht Mitglieder von JustTheMonths.

Aber wenn ich 4 an diesen Code übergeben, identifiziert es es korrekt als Mitglied des gesamten Satzes, aber identifiziert es falsch als ein Mitglied der Untergruppe JustTheMonths.

Was mache ich hier falsch? Warum denkt mein Code, dass 4 ein Mitglied von (8 | 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096 | 8172 | 16344) ist?

private void Form1_Load(object sender, EventArgs e) 
    { 
     FloweringMonth test = FloweringMonth.NotApplicable; 

     if (IsValidFloweringMonthValue((int)test)) 
     { 
      System.Diagnostics.Debug.WriteLine("Valid"); 
     } 
     else 
     { 
      System.Diagnostics.Debug.WriteLine("Not Valid"); 
     } 
    } 

    [Flags] 
    public enum FloweringMonth 
    { 
     Unassigned = 1, Unknown = 2, NotApplicable = 4, 
     Jan = 8, Feb = 16, Mar = 32, Apr = 64, May = 128, Jun = 256, 
     Jul = 512, Aug = 1024, Sep = 2048, Oct = 4086, Nov = 8172, Dec = 16344, 
     JustMonths = (Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec) 
    } 

    public static bool IsValidFloweringMonthValue(int value) 
    { 
     FloweringMonth incoming = (FloweringMonth)value; 

     FloweringMonth AllVals = FloweringMonth.Unassigned | FloweringMonth.Unknown | 
      FloweringMonth.NotApplicable | FloweringMonth.Jan | FloweringMonth.Feb | 
      FloweringMonth.Mar | FloweringMonth.Apr | FloweringMonth.May | 
      FloweringMonth.Jun | FloweringMonth.Jul | FloweringMonth.Aug | 
      FloweringMonth.Sep | FloweringMonth.Oct | FloweringMonth.Nov | FloweringMonth.Dec; 

     // does the incoming value contain any enum values from AllVals? 
     bool HasMembersOfAll = AllVals.HasFlag(incoming); 
     if (!HasMembersOfAll) return false; 

     // does the incoming value contain any enum values from JustTheMonths? 
     bool HasMembersOfMonths = FloweringMonth.JustMonths.HasFlag(incoming); 

     // does it contain any enum values from the set of three exclusive values? 
     FloweringMonth Exclusives = (FloweringMonth.Unassigned | 
      FloweringMonth.Unknown | FloweringMonth.NotApplicable); 
     bool HasMembersOfExclusives = Exclusives.HasFlag(incoming); 

     // an exclusive value cannot be mixed with any month values 
     if (HasMembersOfMonths && HasMembersOfExclusives) return false; // bad combo 

     // an exclusive value cannot be mixed with other exclusive values 
     if (incoming.HasFlag(FloweringMonth.Unassigned) && 
      incoming.HasFlag(FloweringMonth.Unknown)) return false; 
     if (incoming.HasFlag(FloweringMonth.Unassigned) && 
      incoming.HasFlag(FloweringMonth.NotApplicable)) return false; 
     if (incoming.HasFlag(FloweringMonth.Unknown) && 
      incoming.HasFlag(FloweringMonth.NotApplicable)) return false; 

     return true; 
    } 
+0

Von https://msdn.microsoft.com/en-us/library/system.enum(v=vs.110).aspx: . . Definieren Sie Aufzählungskonstanten in Zweierpotenzen, dh 1, 2, 4, 8 und so weiter. Dies bedeutet, dass die einzelnen Flags in kombinierten Aufzählungskonstanten nicht überlappen. –

+0

@ m-y Ähm, nein. Der Compiler ordnet '0, 1, 2, 3, 4, ...' in Abwesenheit von expliziten Werten zu. Das Attribut "Flags" ändert dieses Verhalten nicht. –

+0

@KennethK .: Ich stehe korrigiert, du hast Recht. –

Antwort

2

Ihre Vielfachen von 2 sind falsch. 4086 sollte 4096, 81728192 sein sollte, etc ...

+2

um diese Art von Fehler zu vermeiden, nutzen Sie die Macht von zwei. Zum Beispiel: 'Nicht zugewiesen = 2^0, Unbekannt = 2^1, NichtAnwendbar = 2^2, Jan = 2^3, Feb = 2^4,' ... – kurakura88

+0

Gott. Wie könnte ich das vermissen? Vielen Dank! Hör auf meine eigene Mathe spät in der Nacht zu tun ... @ Kurakura88, brillante Idee. –

+0

@ kurakura88 C# hat keinen PowerOf-Operator; Was Sie vorgeschlagen haben ("^") ist ein bitweiser Operator. Netter subtiler Fehler, den du mir gabst, der hat sich etwas abgewickelt. Müssen Sie die statische Math.Pow-Methode verwenden. Vielleicht möchtest du deine Antwort editieren, die ich gerade genüsslich in meinen Code kopiert habe :-) –

2

Nach @dukedukes beantworten, das Problem war, da Ihr ein Vielfaches von 2 ausgeschaltet waren.

Eine Möglichkeit, diesen Fehler zu vermeiden, ist die Verwendung von bitwise Operationen auf der rechten Seite.

[Flags] 
enum Months 
{ 
    January = 1 << 3, // 8 
    February = 1 << 4, // 16 
    March = 1 << 5, // 32 
} 
+2

Sie meinten '1 << 0' und' 1 << 1' und '1 << 2'? – zerkms

+0

@zerkms, ja. Ich tat. Vielen Dank. Ich hatte das Muster eine Weile nicht benutzt. – Dennis

Verwandte Themen