Удалить привилегии enum флаги правильный путь в 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
}
эти значения привязаны к флажкам в GUI с преобразователем значений. (Я хотел сделать это как можно более общим, потому что есть также различные привилегии [например, 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());
}
}
это работает очень хорошо для отображения и добавления привилегий пользователю в GUI. Также он работает для удаления Суперфлагов, таких как Supervisor (все флаги >=
руководитель удаляются, другие флаги не меняются).
проблема в том, когда я снимаю флажок импорт, например, я хочу удалить все Суперфлаги (Супервизор, администратор), но хотел бы сохранить другие флаги (просмотр, экспорт).
0001 1111 // Admin
0000 0010 // Import
---------
0000 0101 // View | Export
но я не придумал, как это сделать. Любой мальчик, у которого есть хорошее решение для этого?
3 ответов
Если я понимаю, что вы хотите, это должно сделать работу
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);
}
если я правильно понял, вы хотите удалить Supervisor
и Admin
так:
UserPrivileges newPrivileges = (UserPrivileges)(((byte)currentPrivileges) & 7;
он будет работать следующим образом:
0001 1111 // Admin
0000 0111 // 7 flag
---------
0000 0111 // Remain only where 7 bit was set.
другой пример
0000 0011 // View | Import
0000 0111 // 7 flag
---------
0000 0011 // Remain only where 7 bit was set.
по-прежнему я имею в виду, что где 7
флаг установлен, он сохранит значение в результате (beein 0
или 1
). И где 7
флаг 0
это убьет значение 0
.
Mfz привел меня на правильный путь, но это было недостаточно общим для меня, поэтому я придумал другое решение:
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;
}
Я просто получил все не суперфлаги для типа перечисления, и они удалили только суперфлаги, а затем удалили флаг.