2013-06-05 10 views
6

mam typu enum dla uprawnień użytkownika, który wygląda tak:Usuń przywilej flagi enum właściwy sposób w C#

[Flags] 
public enum UserPrivileges : byte 
{ 
    None = 0,          // 0000 0000 
    View = 1 << 0,        // 0000 0001 
    Import = 1 << 1,        // 0000 0010 
    Export = 1 << 2,        // 0000 0100 
    Supervisor = View | Import | Export | 1 << 3, // 0000 1111 
    Admin = Supervisor | 1 << 4     // 0001 1111 
} 

Wartości te są zobowiązane do wyboru w GUI z przetwornikiem wartości. (Chciałem zrobić to jako rodzajowy, jak to możliwe, ponieważ istnieją również różne przywileje [np EmployeePrivileges])

public class ByteFlagsEnumValueConverter : IValueConverter 
{ 
    private byte _targetValue; 

    public object Convert(object value, Type targetType, 
          object parameter, CultureInfo culture) 
    { 
     var mask = (byte)parameter; 
     _targetValue = (byte)value; 
     return ((mask | _targetValue) == _targetValue); 
    } 

    public object ConvertBack(object value, Type targetType, 
           object parameter, CultureInfo culture) 
    { 
     var mask = (byte)parameter; 

     if ((bool)value) 
     { 
      _targetValue |= mask; 
     } 
     else 
     { 
      // Get next superflag for mask (e.g. 0110 -> 1111) 
      var b = mask; 
      b--; 
      b |= (byte)(b >> 1); 
      b |= (byte)(b >> 2); 
      b |= (byte)(b >> 4); 
      b |= (byte)(b >> 8); 

      // if you remove a superflag (e.g. 1111) also remove 
      // everything higher than this flag 
      if (mask == b || mask == 1) 
       _targetValue &= (byte)(mask >> 1); 
      else 
       // ???????? 
     } 

     return Enum.Parse(targetType, _targetValue.ToString()); 
    } 
} 

To działa bardzo dobrze dla wyświetlania i dodawania uprawnień użytkownika w GUI. Działa również w celu usuwania Superflagów takich jak Supervisor (wszystkie flagi >= Supervisora ​​zostają usunięte, pozostałe flagi się nie zmieniają).

Problem polega na tym, że odznaczam Importuj, na przykład, chcę usunąć wszystkie Superflagi (Supervisor, Admin), ale chcę zachować pozostałe flagi (View, Export).

0001 1111 // Admin 
0000 0010 // Import 
--------- 
0000 0101 // View | Export 

Ale nie wpadłem na dobry pomysł, jak to osiągnąć. Anyboy, który ma dobre rozwiązanie?

+0

Czy próbujesz uniknąć używania logiki warunkowej? Jeśli zaczniesz kodować to za pomocą instrukcji if/else, to całkiem proste. – Candide

+0

W twoim przykładzie - chcesz usunąć "Admin" i "Import"? – Mzf

+0

@Candide Chcę zachować to jako ogólne, jak to możliwe, więc mógłbym użyć tego również dla innych projektów lub różnych przywilejów. – Staeff

Odpowiedz

0

Mfz przyniósł mi na dobrej drodze, ale to nie wystarczyło rodzajowy dla mnie, więc ja przyszedłem z innego rozwiązania:

public object ConvertBack(object value, Type targetType, 
           object parameter, CultureInfo culture) 
    { 
     var mask = (byte)parameter; 

     if ((bool)value) 
     { 
      _targetValue |= mask; 
     } 
     else 
     { 
      if (IsSuperFlag(mask) && mask != 1) 
       _targetValue &= (byte)(mask >> 1); 
      else 
      { 
       // Get all flags from enum type that are no SuperFlags 
       var flags = Enum.GetValues(targetType).Cast<Enum>(); 
       flags = flags.Where(x => !IsSuperFlag(System.Convert.ToByte(x))); 

       long nonSuperFlags = 0; 

       foreach (var flag in flags) 
       { 
        nonSuperFlags |= System.Convert.ToByte(flag); 
       } 

       // Now only remove everything except the nonSuperFlags 
       // and then remove the mask 
       _targetValue &= (byte)(~(_targetValue^nonSuperFlags | mask)); 

      } 
     } 

     return Enum.Parse(targetType, _targetValue.ToString()); 
    } 

    private bool IsSuperFlag(byte flag) 
    { 
     var b = flag; 
     b--; 
     b |= (byte)(b >> 1); 
     b |= (byte)(b >> 2); 
     b |= (byte)(b >> 4); 
     b |= (byte)(b >> 8); 

     return b == flag; 
    } 

po prostu dostał wszystkie nie superflags dla typu wyliczeniowego i je usunąć tylko superflagi, a następnie usunięto flagę.

+1

+1. Byłem w drodze robiąc coś podobnego. – Mzf

+0

To bardzo daleko od najlepszej drogi. Ale skoro osiągasz swój cel, to jest sprawa. –

2

Jeśli dobrze rozumiem, co chcesz, to powinno załatwić sprawę

byte tmp = 1 << 3 | 1 << 4; 
    byte removeSuperFlagMask = (byte) (~tmp); 

    byte notSuperflagsMask = 1 << 3 | 1 << 2 | 1 << 1; 
    if ((valueToRemove & notSuperflagsMask) != 0) 
    { 
     newValue = (byte)(removeSuperFlagMask & currentValue & ~valueToRemove); 
    } 
+0

Dziękuję za zaproszenie do pomysłu, ale potrzebowałem bardziej ogólnego rozwiązania. Zobacz moją odpowiedź. – Staeff

1

Jeśli dobrze zrozumiałem chcesz usunąć Supervisor i Admin tak:

UserPrivileges newPrivileges = (UserPrivileges)(((byte)currentPrivileges) & 7; 

To będzie wykonać tak:

0001 1111 // Admin 
0000 0111 // 7 flag 
--------- 
0000 0111 // Remain only where 7 bit was set. 

Inny przykład:

0000 0011 // View | Import 
0000 0111 // 7 flag 
--------- 
0000 0011 // Remain only where 7 bit was set. 

By pozostać To znaczy, że jeżeli 7 flaga jest ustawiona będzie utrzymywać wartość w wyniku (beein 0 lub 1). I gdzie flaga 7 jest 0, zabije wartość do 0.