简体   繁体   English

删除权限枚举标记在C#中正确的方式

[英]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: 如果我理解正确你想删除SupervisorAdmin

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 01 )。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM