2013-06-05 18 views
6

Ho un tipo enum per i privilegi utente che assomiglia a questo:Rimuovi privilegio enum bandiere nel modo giusto in 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 
} 

Questi valori sono destinati a CheckBoxes nella GUI con un convertitore di valori. (Ho voluto fare questo il più generico possibile, perché ci sono anche diversi privilegi [es] 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()); 
    } 
} 

Questo funziona davvero bene per la visualizzazione e l'aggiunta di privilegi per l'utente nella GUI. Funziona anche per rimuovere Superflags come Supervisor (tutti i flag >= vengono rimossi Supervisor, gli altri flag non cambiano).

Il problema è quando deseleziono Importa, ad esempio, voglio rimuovere tutti i Superflags (Supervisore, Amministratore) ma vorrei mantenere gli altri flag (Visualizza, Esporta).

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

Ma non ho idea di come ottenere ciò. Anyboy che ha una buona soluzione per questo?

+0

Stai cercando di evitare l'uso della logica condizionale? Se inizi a scrivere questo codice con istruzioni if ​​/ else, è piuttosto semplice. – Candide

+0

Nel tuo esempio: ti piace rimuovere 'Admin' e' Importa'? – Mzf

+0

@Candide Voglio mantenerlo il più generico possibile, quindi potrei usarlo anche per altri progetti o privilegi diversi. – Staeff

risposta

0

Mfz mi ha portato sulla strada giusta, ma, non è stato sufficientemente generico per me, così mi si avvicinò con un'altra soluzione:

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; 
    } 

ho semplicemente avuto tutti i non superflags per il tipo enum e rimosso solo i superflags e in seguito hanno rimosso la bandiera.

+1

+1. Stavo facendo qualcosa di simile. – Mzf

+0

È molto lontano dal modo migliore. Ma dal momento che raggiungi il tuo obiettivo è questo il problema. –

2

Se ho capito quello che vuoi, questo dovrebbe fare il lavoro

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

Grazie per avermi fatto venire l'idea, ma avevo bisogno di una soluzione più generica. Vedi la mia risposta. – Staeff

1

Se ho capito bene che si desidera rimuovere Supervisor e Admin così:

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

esso deve svolgere in questo modo:

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

Un altro esempio

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

Con rimangono intendo che quando è impostato 7 bandiera persisterà il valore del risultato (beein 0 o 1). E dove il flag 7 è 0, il valore verrà annullato a 0.