[英]Remove privilege enum flags the right way in C#
I have an enum type for user privileges that looks like this: 我有一个用户权限的枚举类型,如下所示:
[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
}
These values are bound to CheckBoxes in the GUI with a value converter. 这些值通过值转换器绑定到GUI中的CheckBoxes。 (I wanted to do this as generic as possible because there are also different privileges [eg EmployeePrivileges]) (我希望这样做尽可能通用,因为还有不同的权限[例如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());
}
}
This works really fine for displaying and adding privileges to the user in the GUI. 这对于在GUI中向用户显示和添加权限非常有用。 Also it works for removing Superflags like Supervisor (all flags >=
Supervisor get removed, the other flags don't change). 它也适用于删除超级标志,如Supervisor(所有标志>=
Supervisor被删除,其他标志不会更改)。
The problem is when I uncheck Import for example, I want to remove all Superflags (Supervisor, Admin) but would like to keep the other flags (View, Export). 问题是当我取消选中导入时,例如,我想删除所有Superflags(Supervisor,Admin)但是想保留其他标志(View,Export)。
0001 1111 // Admin
0000 0010 // Import
---------
0000 0101 // View | Export
But I haven't come up with an good idea how to accomplish this. 但我还没有想出如何实现这一目标。 Anyboy who has a good solution for this? Anyboy谁有一个很好的解决方案?
If I understand what you want , this should do the job 如果我明白你想要什么,这应该可以胜任
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);
}
If I understood correctly you want to remove Supervisor
and Admin
so: 如果我理解正确你想删除Supervisor
和Admin
:
UserPrivileges newPrivileges = (UserPrivileges)(((byte)currentPrivileges) & 7;
It will perform like this: 它会像这样执行:
0001 1111 // Admin
0000 0111 // 7 flag
---------
0000 0111 // Remain only where 7 bit was set.
Another example 另一个例子
0000 0011 // View | Import
0000 0111 // 7 flag
---------
0000 0011 // Remain only where 7 bit was set.
By remain I mean that where 7
flag is set it will persist the value in the result (beein 0
or 1
). 保留我的意思是,如果设置7
标志,它将保持结果中的值(beein 0
或1
)。 And where the 7
flag is 0
it will kill the value to 0
. 如果7
标志为0
,它将把值杀死为0
。
Mfz brought me on the right way but, it wasn't generic enough for me, so I came up with another solution: 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;
}
I simply got all non superflags for the enum type and them removed only the superflags and afterwards removed the flag. 我只是为枚举类型获得了所有非超级标志,并且它们只删除了超级标志,然后删除了标志。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.