비트 마스크 (플래그) 열거 형이 너무 커지면 수행 할 작업


81

내 응용 프로그램에 Flags 열거로 나타내는 매우 큰 권한 집합이 있습니다. long 데이터 유형의 실제 상한에 빠르게 접근하고 있습니다. 그리고 조만간 다른 구조로 전환하기위한 전략을 마련해야합니다. 이제이 목록을 더 작은 조각으로 나눌 수 있지만 이것은 이미 애플리케이션 레이아웃을 기반으로 한 애플리케이션에 대한 전체 권한의 하위 집합에 불과합니다. 우리는 권한을 관리 할 때 표시 목적으로이 구분을 광범위하게 사용하며, 피할 수 있다면 지금 코드를 다시 방문 할 필요가 없습니다.

다른 사람이이 문제를 겪은 적이 있습니까? 어떻게 지나쳤습니까? 일반적인 예제는 괜찮지 만 작업을 수행하기 위해 사용할 수있는 언어 별 트릭이있는 경우 ac # 특정 예제에 가장 관심이 있습니다.

필요하지 않을 수도 있지만 여기에 내가 다루는 앱 부분에 대해 현재 정의 된 권한 목록이 있습니다.

//Subgroup WebAgent
[Flags]
public enum WebAgentPermission : long
{
    [DescriptionAttribute("View Rule Group")]
    ViewRuleGroup = 1,
    [DescriptionAttribute("Add Rule Group")]
    AddRuleGroup = 2,
    [DescriptionAttribute("Edit Rule Group")]
    EditRuleGroup = 4,
    [DescriptionAttribute("Delete Rule Group")]
    DeleteRuleGroup = 8,
    [DescriptionAttribute("View Rule")]
    ViewRule = 16,
    [DescriptionAttribute("Add Rule")]
    AddRule = 32,
    [DescriptionAttribute("Edit Rule")]
    EditRule = 64,
    [DescriptionAttribute("Delete Rule")]
    DeleteRule = 128,
    [DescriptionAttribute("View Location")]
    ViewLocation = 256,
    [DescriptionAttribute("Add Location")]
    AddLocation = 512,
    [DescriptionAttribute("Edit Location")]
    EditLocation = 1024,
    [DescriptionAttribute("Delete Location")]
    DeleteLocation = 2048,
    [DescriptionAttribute("View Volume Statistics")]
    ViewVolumeStatistics = 4096,
    [DescriptionAttribute("Edit Volume Statistics")]
    EditVolumeStatistics = 8192,
    [DescriptionAttribute("Upload Volume Statistics")]
    UploadVolumeStatistics = 16384,
    [DescriptionAttribute("View Role")]
    ViewRole = 32768,
    [DescriptionAttribute("Add Role")]
    AddRole = 65536,
    [DescriptionAttribute("Edit Role")]
    EditRole = 131072,
    [DescriptionAttribute("Delete Role")]
    DeleteRole = 262144,
    [DescriptionAttribute("View User")]
    ViewUser = 524288,
    [DescriptionAttribute("Add User")]
    AddUser = 1048576,
    [DescriptionAttribute("Edit User")]
    EditUser = 2097152,
    [DescriptionAttribute("Delete User")]
    DeleteUser = 4194304,
    [DescriptionAttribute("Assign Permissions To User")]
    AssignPermissionsToUser = 8388608,
    [DescriptionAttribute("Change User Password")]
    ChangeUserPassword = 16777216,
    [DescriptionAttribute("View Audit Logs")]
    ViewAuditLogs = 33554432,
    [DescriptionAttribute("View Team")]
    ViewTeam = 67108864,
    [DescriptionAttribute("Add Team")]
    AddTeam = 134217728,
    [DescriptionAttribute("Edit Team")]
    EditTeam = 268435456,
    [DescriptionAttribute("Delete Team")]
    DeleteTeam = 536870912,
    [DescriptionAttribute("View Web Agent Reports")]
    ViewWebAgentReports = 1073741824,
    [DescriptionAttribute("View All Locations")]
    ViewAllLocations = 2147483648,
    [DescriptionAttribute("Access to My Search")]
    AccessToMySearch = 4294967296,
    [DescriptionAttribute("Access to Pespective Search")]
    AccessToPespectiveSearch = 8589934592,
    [DescriptionAttribute("Add Pespective Search")]
    AddPespectiveSearch = 17179869184,
    [DescriptionAttribute("Edit Pespective Search")]
    EditPespectiveSearch = 34359738368,
    [DescriptionAttribute("Delete Pespective Search")]
    DeletePespectiveSearch = 68719476736,
    [DescriptionAttribute("Access to Search")]
    AccessToSearch = 137438953472,
    [DescriptionAttribute("View Form Roles")]
    ViewFormRole = 274877906944,
    [DescriptionAttribute("Add / Edit Form Roles")]
    AddFormRole = 549755813888,
    [DescriptionAttribute("Delete UserFormRolesDifferenceMasks")]
    DeleteFormRole = 1099511627776,
    [DescriptionAttribute("Export Locations")]
    ExportLocations = 2199023255552,
    [DescriptionAttribute("Import Locations")]
    ImportLocations = 4398046511104,
    [DescriptionAttribute("Manage Location Levels")]
    ManageLocationLevels = 8796093022208,
    [DescriptionAttribute("View Job Title")]
    ViewJobTitle = 17592186044416,
    [DescriptionAttribute("Add Job Title")]
    AddJobTitle = 35184372088832,
    [DescriptionAttribute("Edit Job Title")]
    EditJobTitle = 70368744177664,
    [DescriptionAttribute("Delete Job Title")]
    DeleteJobTitle = 140737488355328,
    [DescriptionAttribute("View Dictionary Manager")]
    ViewDictionaryManager = 281474976710656,
    [DescriptionAttribute("Add Dictionary Manager")]
    AddDictionaryManager = 562949953421312,
    [DescriptionAttribute("Edit Dictionary Manager")]
    EditDictionaryManager = 1125899906842624,
    [DescriptionAttribute("Delete Dictionary Manager")]
    DeleteDictionaryManager = 2251799813685248,
    [DescriptionAttribute("View Choice Manager")]
    ViewChoiceManager = 4503599627370496,
    [DescriptionAttribute("Add Choice Manager")]
    AddChoiceManager = 9007199254740992,
    [DescriptionAttribute("Edit Chioce Manager")]
    EditChoiceManager = 18014398509481984,
    [DescriptionAttribute("Delete Choice Manager")]
    DeleteChoiceManager = 36028797018963968,
    [DescriptionAttribute("Import Export Choices")] //57
    ImportExportChoices = 72057594037927936
}

70
명확성을 위해 나는 보통 다음을 사용합니다 : (1 << 0), (1 << 1), .. (1 << 57) 내 깃발. 이해하기 쉽고 가치를 잘못 이해하기가 더 어렵습니다. 그래도 질문에 대답하지 않습니다.
Talljoe 2009-06-29

감사합니다. 비슷한 작업을 수행하기 위해 몇 가지 방법을 시도했지만 항상 열거 형 오류에 대해 계산 된 값을 사용할 수 없습니다.
Matthew Vines

4
^이 의미하는 바를 의미하지 않는다고 생각합니다.
Eric Lippert

28
긴 비트 시프트를 원하면 컴파일러에게 원하는 것을 알려주십시오. (1L << 40) 잘 작동합니다.
Eric Lippert

1
음, explative, 뭔가를 가리키는에 다시 한번 나는이를 통해 돌진 무엇을 얻을 즉,의, 감사 바보 나는 밖으로 : 한
마태 복음 덩굴

답변:


41

나는 거기에 적어도 소수의 다른 열거의 값을 봅니다.

내 첫번째 생각은 논리적 그룹에 권한을 분할하여 문제에 접근하는 것이 었습니다 ( RuleGroupPermissions, RulePermissions, LocationPermissions, ...), 다음 (클래스를 가진 WebAgentPermissions각각의 권한 열거 유형에 대한 속성을 노출).

권한 값이 반복적으로 보이기 때문에 결국 하나의 열거 형으로 끝날 수 있습니다.

[Flags]
public enum Permissions
{
    View = 1,
    Add = 2,
    Edit = 4,
    Delete = 8
}

그런 다음 WebAgentPermissions클래스가 권한을 설정할 각 영역에 대한 속성을 노출하도록합니다.

class WebAgentPermissions
{
    public Permissions RuleGroup { get; set; }
    public Permissions Rule { get; set; }
    public Permissions Location { get; set; }
    // and so on...
}

2
나는 이것을 좋아하고 꽤 표준이지만이 솔루션을 다소 번거롭게 만들기에는 충분한 편차가 있다고 생각합니다. 결국 나는 그것을 빨아 들이고이 짐승을 더 작은 조각으로 나누고 변경 사항을 처리하기 위해 내 응용 프로그램의 몇 섹션을 다시 엔지니어링해야 할 것이라고 생각합니다. 나는 내가 찾지 못한 마법의 총알이 밖에 있기를 바랐습니다. 시간 내 줘서 고마워.
Matthew Vines

2
이 경우에는 꽤 좋은 솔루션입니다. 불행히도 그것은 '열거 형 의미의 최고로 분할하려고 시도'하는 것을 제외하고는 유사한 문제를 다루는 일반적인 방법을 제공하지 않습니다.
PPC

가능한 작업이 CRUD가 아니라면 여러 권한 열거 형이 필요할 수 있습니다. 이 모든 것을 db에 저장하려고 시도하는 것은 상상할 수 없으며 사용자의 권한이 필요할 때마다 수많은 테이블을 조인하게 될 것입니다.
perustaja

25

언어 문서는 다음과 같이 말합니다.

http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx

"기본 유형은 Int32이므로 최대 단일 비트 플래그는 1073741824이고 각 열거 형에 대해 총 32 개의 플래그가 있습니다."

그러나 ... 업데이트 :

댓글 작성자가 정확합니다. 이것을 확인하십시오 :

http://msdn.microsoft.com/en-us/library/ms182147(VS.80).aspx

Int32는 DEFAULT 데이터 유형일뿐입니다! 실제로 Int64를 지정할 수 있습니다.

public enum MyEnumType : Int64

... 최대 64 개의 값을 허용합니다. 그러나 그것은 확실히 최대 인 것 같습니다. 그 후에는 리엔지니어링을 살펴볼 것입니다. 나머지 솔루션에 대해 너무 많이 알지 못하면 정확히 무엇이 적합할지 말할 수 없습니다. 그러나 권한 식별자의 배열 (또는 해시 맵)은 아마도 가장 자연스러운 접근 방식 일 것입니다.


귀하가 게시 한 인용문은 댓글 작성자의 말이며 그가 잘못되었다고 생각합니다. Flag 속성은 유형 정보를 전혀 지정하지 않습니다. 형식을 명시 적으로 지정하지 않으면 열거 형은 기본적으로 Int32입니다.
Matthew Vines

4
@PatrickM은 안타깝게도 훌륭한 일화이지만 현실이 아니며 더 필요합니다.
leigero 2015

이 답변에 언급 된 인용문은 더 이상 가져온 페이지에없는 것 같습니다.
Panzercrisis

1
@MatthewVines가 지정 public enum WebAgentPermission : long했고 사용과 동일합니다Int64
Ogglas

@leigero 저에게 디자인 냄새를 비명 tbh. 이러한 값을 분해하거나 구조를 변경하는 방법을 살펴 볼까요? 예를 들어 권한 용인 경우이 구조에 바이너리를 사용해야하는 특별한 이유가없는 한 대신 클레임을 사용하는 것이 좋습니다. 바이너리를 사용해야하더라도 여러 필드 (예 :)에서 비트 연산을 수행 할 수 있습니다 ((p.group | p.location) & MY_PERMISSION) == MY_PERMISSION.
Sinaesthetic

14

BitArray 클래스 를 확인할 수 있습니다 . 아마도 당신은 나중에 그것을 사용할 것입니다.


이것은 좋은 옵션이지만 물론 다른 포스터가 제안한 것처럼 모든 비트에 이름을 부여하는 클래스로 캡슐화해야합니다.
Doug McClean

BitArray 클래스는 이상적입니다. 권한에 대한 공용 열거 형 (0에서 시작하는 연속 정수)을 사용하여 클래스를 정의하고 권한 열거에 의해 인덱싱 된 개인 BitArray 멤버의 값을 반환하는 쿼리 함수가 있습니다. 이것은 임의의 수의 권한을 효율적으로 처리합니다.
Stephen C. Steel

좋은. 그리고 1.0에서 다시 지원됩니다.
HelloSam 2013

1
@중재인. 이것은 흥미로운 해결책입니다. 값이 DB에 저장 될 때 비트가 있는지 확인하려면 어떻게해야합니까?
Paul Fleming

10

이것은 내가 생각했던 것보다 더 일반적인 문제로 판명되었습니다. CSS 클래스를 플래그 유형으로 표현하고 64 개 이상의 가능성이있었습니다. 나는 그 과정에서 배운 모든 것을 가져 와서 재사용 가능한 패턴으로 바꿨다. 비록 그것이 구조체이기 때문에 복사-붙여 넣기 유형 패턴이긴하지만.

이것이 BigFlags"열거 형"입니다. BigIntegerfrom을 사용하거나 System.Numerics해당 어셈블리를 참조 할 수있는 방법이없는 경우 전 처리기 지시문을 BitArray해제하여 사용하는 대체 방법이 있습니다 NUMERICS.

그것은 현저히처럼 동작 Flags도 같은 것들을 정의, 열거 HasFlag(...), GetNames(), GetValues(), TryParse(...)하는 TypeConverter, IConvertible등 그것은 정의 않기 때문에 TypeConverter그리고 IConvertible, 그것은 또한 항상 문자열이나 텍스트 데이터 형식이기는하지만, 데이터 저장소에 저장하기에 적합합니다.

"열거 형"값을 public static readonly멤버 로 노출합니다 . 결합 된 열거 형 값은 가져 오기 전용 속성으로 노출됩니다.

이를 사용하려면 코드를 복사하여 붙여 넣은 다음 검색을 수행하고 BigFlags구조체 이름으로 바꾼 다음 TODO섹션 에서 열거 형을 삭제하고 값을 추가합니다.

누군가가 유용하다고 생각하기를 바랍니다.

#define NUMERICS

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
#if NUMERICS
using System.Numerics;
#endif
using System.Reflection;
using System.Text;
using System.Threading.Tasks;


namespace Aim
{
    /// <summary>
    /// The BigFlags struct behaves like a Flags enumerated type.
    /// <para>
    /// Note that if this struct will be stored in some type of data
    /// store, it should be stored as a string type. There are two
    /// reasons for this:
    /// </para>
    /// <para>
    /// 1. Presumably, this pattern is being used because the number
    /// of values will exceed 64 (max positions in a long flags enum).
    /// Since this is so, there is in any case no numeric type which
    /// can store all the possible combinations of flags.
    /// </para>
    /// <para>
    /// 2. The "enum" values are assigned based on the order that the
    /// static public fields are defined. It is much safer to store
    /// these fields by name in case the fields are rearranged. This
    /// is particularly important if this represents a permission set!
    /// </para>
    /// </summary>
    [
    TypeConverter( typeof( BigFlagsConverter ) )
    ]
    public struct BigFlags : IEquatable<BigFlags>,
        IComparable<BigFlags>, IComparable, IConvertible
    {
        #region State...

        private static readonly List<FieldInfo> Fields;
        private static readonly List<BigFlags> FieldValues;
#if NUMERICS
        private static readonly bool ZeroInit = true;
        private BigInteger Value;

        /// <summary>
        /// Creates a value taking ZeroInit into consideration.
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private static BigInteger CreateValue( int index )
        {
            if( ZeroInit && index == 0 )
            {
                return 0;
            }
            int idx = ZeroInit ? index - 1 : index;

            return new BigInteger( 1 ) << idx;
        }
#else
        private BitArray Array;

        /// <summary>
        /// Lazy-initialized BitArray.
        /// </summary>
        private BitArray Bits
        {
            get
            {
                if( null == Array )
                {
                    Array = new BitArray( Fields.Count );
                }
                return Array;
            }
        }
#endif
        #endregion ...State

        #region Construction...

        /// <summary>
        /// Static constructor. Sets the static public fields.
        /// </summary>
        static BigFlags()
        {
            Fields = typeof( BigFlags ).GetFields(
                BindingFlags.Public | BindingFlags.Static ).ToList();
            FieldValues = new List<BigFlags>();
            for( int i = 0; i < Fields.Count; i++ )
            {
                var field = Fields[i];
                var fieldVal = new BigFlags();
#if NUMERICS
                fieldVal.Value = CreateValue( i );
#else
                fieldVal.Bits.Set( i, true );
#endif
                field.SetValue( null, fieldVal );
                FieldValues.Add( fieldVal );
            }
        }
        #endregion ...Construction

        #region Operators...

        /// <summary>
        /// OR operator. Or together BigFlags instances.
        /// </summary>
        /// <param name="lhs"></param>
        /// <param name="rhs"></param>
        /// <returns></returns>
        public static BigFlags operator |( BigFlags lhs, BigFlags rhs )
        {
            var result = new BigFlags();
#if NUMERICS
            result.Value = lhs.Value | rhs.Value;
#else
            // BitArray is modified in place - always copy!
            result.Array = new BitArray( lhs.Bits ).Or( rhs.Bits );
#endif

            return result;
        }

        /// <summary>
        /// AND operator. And together BigFlags instances.
        /// </summary>
        /// <param name="lhs"></param>
        /// <param name="rhs"></param>
        /// <returns></returns>
        public static BigFlags operator &( BigFlags lhs, BigFlags rhs )
        {
            var result = new BigFlags();
#if NUMERICS
            result.Value = lhs.Value & rhs.Value;
#else
            // BitArray is modified in place - always copy!
            result.Array = new BitArray( lhs.Bits ).And( rhs.Bits );
#endif

            return result;
        }

        /// <summary>
        /// XOR operator. Xor together BigFlags instances.
        /// </summary>
        /// <param name="lhs"></param>
        /// <param name="rhs"></param>
        /// <returns></returns>
        public static BigFlags operator ^( BigFlags lhs, BigFlags rhs )
        {
            var result = new BigFlags();
#if NUMERICS
            result.Value = lhs.Value ^ rhs.Value;
#else
            // BitArray is modified in place - always copy!
            result.Array = new BitArray( lhs.Bits ).Xor( rhs.Bits );
#endif

            return result;
        }

        /// <summary>
        /// Equality operator.
        /// </summary>
        /// <param name="lhs"></param>
        /// <param name="rhs"></param>
        /// <returns></returns>
        public static bool operator ==( BigFlags lhs, BigFlags rhs )
        {
            return lhs.Equals( rhs );
        }

        /// <summary>
        /// Inequality operator.
        /// </summary>
        /// <param name="lhs"></param>
        /// <param name="rhs"></param>
        /// <returns></returns>
        public static bool operator !=( BigFlags lhs, BigFlags rhs )
        {
            return !( lhs == rhs );
        }
        #endregion ...Operators

        #region System.Object Overrides...

        /// <summary>
        /// Overridden. Returns a comma-separated string.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
#if NUMERICS
            if( ZeroInit && Value == 0 )
            {
                return Fields[0].Name;
            }
#endif
            var names = new List<string>();
            for( int i = 0; i < Fields.Count; i++ )
            {
#if NUMERICS
                if( ZeroInit && i == 0 )
                    continue;

                var bi = CreateValue( i );
                if( ( Value & bi ) ==  bi )
                    names.Add( Fields[i].Name );
#else
                if( Bits[i] )
                    names.Add( Fields[i].Name );
#endif
            }

            return String.Join( ", ", names );
        }

        /// <summary>
        /// Overridden. Compares equality with another object.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals( object obj )
        {
            if( obj is BigFlags )
            {
                return Equals( (BigFlags)obj );
            }

            return false;
        }

        /// <summary>
        /// Overridden. Gets the hash code of the internal BitArray.
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
#if NUMERICS
            return Value.GetHashCode();
#else
            int hash = 17;
            for( int i = 0; i < Bits.Length; i++ )
            {
                if( Bits[i] )
                    hash ^= i;
            }

            return hash;
#endif
        }
        #endregion ...System.Object Overrides

        #region IEquatable<BigFlags> Members...

        /// <summary>
        /// Strongly-typed equality method.
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool Equals( BigFlags other )
        {
#if NUMERICS
            return Value == other.Value;
#else
            for( int i = 0; i < Bits.Length; i++ )
            {
                if( Bits[i] != other.Bits[i] )
                    return false;
            }

            return true;
#endif
        }
        #endregion ...IEquatable<BigFlags> Members

        #region IComparable<BigFlags> Members...

        /// <summary>
        /// Compares based on highest bit set. Instance with higher
        /// bit set is bigger.
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public int CompareTo( BigFlags other )
        {
#if NUMERICS
            return Value.CompareTo( other.Value );
#else
            for( int i = Bits.Length - 1; i >= 0; i-- )
            {
                bool thisVal = Bits[i];
                bool otherVal = other.Bits[i];
                if( thisVal && !otherVal )
                    return 1;
                else if( !thisVal && otherVal )
                    return -1;
            }

            return 0;
#endif
        }
        #endregion ...IComparable<BigFlags> Members

        #region IComparable Members...

        int IComparable.CompareTo( object obj )
        {
            if( obj is BigFlags )
            {
                return CompareTo( (BigFlags)obj );
            }

            return -1;
        }
        #endregion ...IComparable Members

        #region IConvertible Members...

        /// <summary>
        /// Returns TypeCode.Object.
        /// </summary>
        /// <returns></returns>
        public TypeCode GetTypeCode()
        {
            return TypeCode.Object;
        }

        bool IConvertible.ToBoolean( IFormatProvider provider )
        {
            throw new NotSupportedException();
        }

        byte IConvertible.ToByte( IFormatProvider provider )
        {
#if NUMERICS
            return Convert.ToByte( Value );
#else
            throw new NotSupportedException();
#endif
        }

        char IConvertible.ToChar( IFormatProvider provider )
        {
            throw new NotSupportedException();
        }

        DateTime IConvertible.ToDateTime( IFormatProvider provider )
        {
            throw new NotSupportedException();
        }

        decimal IConvertible.ToDecimal( IFormatProvider provider )
        {
#if NUMERICS
            return Convert.ToDecimal( Value );
#else
            throw new NotSupportedException();
#endif
        }

        double IConvertible.ToDouble( IFormatProvider provider )
        {
#if NUMERICS
            return Convert.ToDouble( Value );
#else
            throw new NotSupportedException();
#endif
        }

        short IConvertible.ToInt16( IFormatProvider provider )
        {
#if NUMERICS
            return Convert.ToInt16( Value );
#else
            throw new NotSupportedException();
#endif
        }

        int IConvertible.ToInt32( IFormatProvider provider )
        {
#if NUMERICS
            return Convert.ToInt32( Value );
#else
            throw new NotSupportedException();
#endif
        }

        long IConvertible.ToInt64( IFormatProvider provider )
        {
#if NUMERICS
            return Convert.ToInt64( Value );
#else
            throw new NotSupportedException();
#endif
        }

        sbyte IConvertible.ToSByte( IFormatProvider provider )
        {
#if NUMERICS
            return Convert.ToSByte( Value );
#else
            throw new NotSupportedException();
#endif
        }

        float IConvertible.ToSingle( IFormatProvider provider )
        {
#if NUMERICS
            return Convert.ToSingle( Value );
#else
            throw new NotSupportedException();
#endif
        }

        string IConvertible.ToString( IFormatProvider provider )
        {
            return ToString();
        }

        object IConvertible.ToType( Type conversionType, IFormatProvider provider )
        {
            var tc = TypeDescriptor.GetConverter( this );

            return tc.ConvertTo( this, conversionType );
        }

        ushort IConvertible.ToUInt16( IFormatProvider provider )
        {
#if NUMERICS
            return Convert.ToUInt16( Value );
#else
            throw new NotSupportedException();
#endif
        }

        uint IConvertible.ToUInt32( IFormatProvider provider )
        {
#if NUMERICS
            return Convert.ToUInt32( Value );
#else
            throw new NotSupportedException();
#endif
        }

        ulong IConvertible.ToUInt64( IFormatProvider provider )
        {
#if NUMERICS
            return Convert.ToUInt64( Value );
#else
            throw new NotSupportedException();
#endif
        }
        #endregion ...IConvertible Members

        #region Public Interface...

        /// <summary>
        /// Checks <paramref name="flags"/> to see if all the bits set in
        /// that flags are also set in this flags.
        /// </summary>
        /// <param name="flags"></param>
        /// <returns></returns>
        public bool HasFlag( BigFlags flags )
        {
            return ( this & flags ) == flags;
        }

        /// <summary>
        /// Gets the names of this BigFlags enumerated type.
        /// </summary>
        /// <returns></returns>
        public static string[] GetNames()
        {
            return Fields.Select( x => x.Name ).ToArray();
        }

        /// <summary>
        /// Gets all the values of this BigFlags enumerated type.
        /// </summary>
        /// <returns></returns>
        public static BigFlags[] GetValues()
        {
            return FieldValues.ToArray();
        }

        /// <summary>
        /// Standard TryParse pattern. Parses a BigFlags result from a string.
        /// </summary>
        /// <param name="s"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public static bool TryParse( string s, out BigFlags result )
        {
            result = new BigFlags();
            if( String.IsNullOrEmpty( s ) )
                return true;

            var fieldNames = s.Split( ',' );
            foreach( var f in fieldNames )
            {
                var field = Fields.FirstOrDefault( x =>
                    String.Equals( x.Name, f.Trim(),
                    StringComparison.OrdinalIgnoreCase ) );
                if( null == field )
                {
                    result = new BigFlags();
                    return false;
                }
#if NUMERICS
                int i = Fields.IndexOf( field );
                result.Value |= CreateValue( i );
#else
                result.Bits.Set( Fields.IndexOf( field ), true );
#endif
            }

            return true;
        }

        //
        // Expose "enums" as public static readonly fields.
        // TODO: Replace this section with your "enum" values.
        //
        public static readonly BigFlags None;
        public static readonly BigFlags FirstValue;
        public static readonly BigFlags ValueTwo;
        public static readonly BigFlags ValueThree;
        public static readonly BigFlags ValueFour;
        public static readonly BigFlags ValueFive;
        public static readonly BigFlags ValueSix;
        public static readonly BigFlags LastValue;

        /// <summary>
        /// Expose flagged combinations as get-only properties.
        /// </summary>
        public static BigFlags FirstLast
        {
            get
            {
                return BigFlags.FirstValue | BigFlags.LastValue;
            }
        }
        #endregion ...Public Interface
    }

    /// <summary>
    /// Converts objects to and from BigFlags instances.
    /// </summary>
    public class BigFlagsConverter : TypeConverter
    {
        /// <summary>
        /// Can convert to string only.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="destinationType"></param>
        /// <returns></returns>
        public override bool CanConvertTo( ITypeDescriptorContext context,
            Type destinationType )
        {
            return destinationType == typeof( String );
        }

        /// <summary>
        /// Can convert from any object.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="sourceType"></param>
        /// <returns></returns>
        public override bool CanConvertFrom( ITypeDescriptorContext context,
            Type sourceType )
        {
            return true;
        }

        /// <summary>
        /// Converts BigFlags to a string.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="culture"></param>
        /// <param name="value"></param>
        /// <param name="destinationType"></param>
        /// <returns></returns>
        public override object ConvertTo( ITypeDescriptorContext context,
            CultureInfo culture, object value, Type destinationType )
        {
            if( value is BigFlags && CanConvertTo( destinationType ) )
                return value.ToString();

            return null;
        }

        /// <summary>
        /// Attempts to parse <paramref name="value"/> and create and
        /// return a new BigFlags instance.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="culture"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public override object ConvertFrom( ITypeDescriptorContext context,
            CultureInfo culture, object value )
        {
            var s = Convert.ToString( value );
            BigFlags result;
            BigFlags.TryParse( s, out result );

            return result;
        }
    }
}

5

C #에서 일종의 열거 형이지만 더 유연한 값을 나타내는 유연한 방법 중 하나는 다음과 같이 미리 조리 된 값을 사용할 수있는 정적 클래스로 나타내는 것입니다.

public sealed class WebAgentPermission
{
    private long ID;

    public static readonly WebAgentPermission
        ViewRuleGroup = new WebAgentPermission { ID = 1 };
    public static readonly WebAgentPermission
        AddRuleGroup  = new WebAgentPermission { ID = 2 };

    private WebAgentPermission() { } 

    // considerations: override equals/gethashcode, probably override tostring,
    // maybe implicit cast to/from long, maybe other stuff
}

또는 그냥 분할하십시오. 정말 시도했다면 할 수있을 것 같습니다.


1
이것은이 문제를 볼 수있는 적절한 방법이며 지금까지 고려하지 않은 방법입니다. 귀하의 의견에 감사드립니다.
Matthew Vines

5

귀하의 질문에 대한 답변이 아니라 관련 제안 : 비트 시프 팅을 사용하여 다음과 같이 숫자 값을 지정합니다.

[Flags]
public enum MyEnumFlags : Int64
{
    None = 0,
    A = 1 << 0,
    B = 1 << 1,
    C = 1 << 2,
    D = 1 << 3,
    E = 1 << 4,
    F = 1 << 5,
    ...etc...

처음 10 개에게는 그다지 중요하지 않지만 그 후에는 정말 편리해집니다.


4

이 응용 프로그램을 제어하는 ​​경우 공통 권한 집합 (보기, 추가, 편집, 삭제, 업로드 / 가져 오기)과 리소스 집합 (사용자, 역할, 규칙 등)이있을 것입니다. 웹 페이지에서 해당 페이지와 관련된 리소스 유형을 찾은 다음 권한을 확인합니다. 아마도 다음과 같습니다.

Permissions perms = agent.GetPermissions(ResourceType.User);
if((perms & Permissions.View) == Permissions.View) { /* do work */ }

또는

Permissions perms = agent.Permissions[ResourceType.User];
if((perms & Permissions.View) == Permissions.View) { /* do work */ }

또는

if(agent.IsAuthorized(ResourceType.User, Permissions.View)) { /* do work */ }

다른 모든 것에는 의미가없는 몇 가지 권한이 있습니다 (사용자에게 권한 할당, 이름 지정). 내가 얼마나 문제를 알지 못 하느냐에 따라 어떻게 처리할지 모르겠다.


위의 댓글에 +1하세요. 시간 내 주셔서 감사합니다.
Matthew Vines

1

나는 이런 상황에 처하지 않았습니다.

내가 생각하는 것은 각 카테고리에 대해 별도의 열거 형을 만들고 매개 변수로 수락합니다.

RuleGroupPermission
    None = 0
    ViewRuleGroup = 1,
    AddRuleGroup = 2,
    EditRuleGroup = 4,
    DeleteRuleGroup = 8,

LocationOperations
    None = 0
    Add = 1
    View = 2
    Delete = 4

void setPermission(RuleGroupPermission ruleGroupOpsAllowed, LocationOperations locationOptions)
{
   ...
}

편집 : messagebox.show가 어떻게하는지보십시오. OK, OKCancel은 질문, 정보, 느낌표와 구분됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.