예제 #1
0
        public EnumCache(Type enumType, IEnumInfoInternal <TInt, TIntProvider> enumInfo)
        {
            _enumTypeName       = enumType.Name;
            EnumInfo            = enumInfo;
            _hasCustomValidator = enumInfo.HasCustomValidator;

            IsFlagEnum = enumType.IsDefined(typeof(FlagsAttribute), false);

            var fields =
#if TYPE_REFLECTION
                enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
#else
                enumType.GetTypeInfo().DeclaredFields.Where(fieldInfo => (fieldInfo.Attributes & (FieldAttributes.Static | FieldAttributes.Public)) == (FieldAttributes.Static | FieldAttributes.Public)).ToArray();
#endif
            _valueMap = new Dictionary <TInt, EnumMemberInternal <TInt, TIntProvider> >(fields.Length);
            if (fields.Length == 0)
            {
                return;
            }
            var duplicateValues = new List <EnumMemberInternal <TInt, TIntProvider> >();
            foreach (var field in fields)
            {
                var value      = (TInt)field.GetValue(null);
                var name       = field.Name;
                var attributes =
#if TYPE_REFLECTION
                    Attribute.GetCustomAttributes(field, false);
#else
                    field.GetCustomAttributes(false).ToArray();
#endif
                var isPrimary = false;
                foreach (var attribute in attributes)
                {
                    if (attribute is PrimaryEnumMemberAttribute)
                    {
                        isPrimary = true;
                        break;
                    }
                }
                var member = new EnumMemberInternal <TInt, TIntProvider>(value, name, attributes, this);
                EnumMemberInternal <TInt, TIntProvider> existing;
                if (_valueMap.TryGetValue(value, out existing))
                {
                    if (isPrimary)
                    {
                        _valueMap[value] = member;
                        member           = existing;
                    }
                    duplicateValues.Add(member);
                }
                else
                {
                    _valueMap.Add(value, member);
                    if (IsPowerOfTwo(value))
                    {
                        AllFlags = Provider.Or(AllFlags, value);
                    }
                }
            }

            // Makes sure is in increasing value order, due to no removals
            var values = _valueMap.ToArray();
            Array.Sort(values, (first, second) => first.Key.CompareTo(second.Key));
            _valueMap = new Dictionary <TInt, EnumMemberInternal <TInt, TIntProvider> >(_valueMap.Count);
            foreach (var pair in values)
            {
                _valueMap.Add(pair.Key, pair.Value);
            }

            _maxDefined   = values[values.Length - 1].Key;
            _minDefined   = values[0].Key;
            _isContiguous = Provider.Subtract(_maxDefined, Provider.Create(_valueMap.Count - 1)).Equals(_minDefined);

            if (duplicateValues.Count > 0)
            {
                // Makes sure is in increasing order
                duplicateValues.Sort((first, second) => first.Value.CompareTo(second.Value));
                _duplicateValues          = duplicateValues;
                _duplicateValues.Capacity = _duplicateValues.Count;
            }
        }
예제 #2
0
        public EnumCache(Type enumType, IEnumInfoInternal <TInt, TIntProvider> enumInfo)
        {
            _enumTypeName       = enumType.Name;
            EnumInfo            = enumInfo;
            _hasCustomValidator = enumInfo.HasCustomValidator;

            IsFlagEnum = enumType.IsDefined(typeof(FlagsAttribute), false);

            var fields =
#if TYPE_REFLECTION
                enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
#else
                enumType.GetTypeInfo().DeclaredFields.Where(fieldInfo => (fieldInfo.Attributes & (FieldAttributes.Static | FieldAttributes.Public)) == (FieldAttributes.Static | FieldAttributes.Public)).ToArray();
#endif
            _valueMap = new Dictionary <TInt, EnumMemberInternal <TInt, TIntProvider> >(fields.Length);
            if (fields.Length == 0)
            {
                return;
            }
            List <EnumMemberInternal <TInt, TIntProvider> > duplicateValues = null;

            // This is necessary due to a .NET reflection bug with retrieving Boolean Enums values
            Dictionary <string, TInt> fieldDictionary = null;
            var isBoolean = typeof(TInt) == typeof(bool);
            if (isBoolean)
            {
                fieldDictionary = new Dictionary <string, TInt>();
                var values = (TInt[])Enum.GetValues(enumType);
                var names  = Enum.GetNames(enumType);
                for (var i = 0; i < names.Length; ++i)
                {
                    fieldDictionary.Add(names[i], values[i]);
                }
            }

            foreach (var field in fields)
            {
                var name       = field.Name;
                var value      = isBoolean ? fieldDictionary[name] : (TInt)field.GetValue(null);
                var attributes = new AttributeCollection(
#if TYPE_REFLECTION
                    Attribute.GetCustomAttributes(field, false));
#else
                    field.GetCustomAttributes(false).ToArray());
#endif
                var member = new EnumMemberInternal <TInt, TIntProvider>(value, name, attributes, this);
                if (_valueMap.TryGetValue(value, out var existing))
                {
                    if (attributes.Has <PrimaryEnumMemberAttribute>())
                    {
                        _valueMap[value] = member;
                        member           = existing;
                    }
                    (duplicateValues ?? (duplicateValues = new List <EnumMemberInternal <TInt, TIntProvider> >())).Add(member);
                }
                else
                {
                    _valueMap.Add(value, member);
                    // Is Power of Two
                    if (Provider.BitCount(value) == 1)
                    {
                        AllFlags = Provider.Or(AllFlags, value);
                    }
                }
            }

            var isInOrder = true;
            var previous  = default(TInt);
            var isFirst   = true;
            foreach (var pair in _valueMap)
            {
                var key = pair.Key;
                if (isFirst)
                {
                    _minDefined = key;
                    isFirst     = false;
                }
                else if (previous.CompareTo(key) > 0)
                {
                    isInOrder = false;
                    break;
                }
                previous = key;
            }
            if (isInOrder)
            {
                _maxDefined = previous;
            }
            else
            {
                // Makes sure is in increasing value order, due to no removals
                var values = _valueMap.ToArray();
                Array.Sort(values, (first, second) => first.Key.CompareTo(second.Key));
                _valueMap = new Dictionary <TInt, EnumMemberInternal <TInt, TIntProvider> >(_valueMap.Count);

                foreach (var pair in values)
                {
                    _valueMap.Add(pair.Key, pair.Value);
                }

                _maxDefined = values[values.Length - 1].Key;
                _minDefined = values[0].Key;
            }

            _isContiguous = Provider.Subtract(_maxDefined, Provider.Create(_valueMap.Count - 1)).Equals(_minDefined);

            if (duplicateValues != null)
            {
                duplicateValues.TrimExcess();
                // Makes sure is in increasing order
                duplicateValues.Sort((first, second) => first.Value.CompareTo(second.Value));
                _duplicateValues          = duplicateValues;
                _duplicateValues.Capacity = _duplicateValues.Count;
            }
        }