6

次のようなユーザー権限の列挙型があります。

[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 の CheckBoxes にバインドされます。(さまざまな特権 [eg 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 でユーザーに特権を表示および追加するのに非常にうまく機能します。また、スーパーバイザーなどのスーパーフラグを削除する場合にも機能します (スーパーバイザーのすべてのフラグ>=が削除され、他のフラグは変更されません)。

問題は、たとえば、インポートのチェックを外すときです。すべてのスーパーフラグ (スーパーバイザー、管理者) を削除したいが、他のフラグ (ビュー、エクスポート) は保持したいです。

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

しかし、私はこれを達成するための良いアイデアを思いつきませんでした。これに対する良い解決策を持っている人はいますか?

4

3 に答える 3

1

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フラグが設定されている場所で結果の値を保持することを意味します ( beein0または1)。そして、7フラグがどこにある0かは、値を に殺します0

于 2013-06-05T13:47:59.550 に答える
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;
    }

列挙型の非スーパーフラグをすべて取得しただけで、スーパーフラグのみが削除され、その後フラグが削除されました。

于 2013-06-06T08:20:39.150 に答える