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; } }
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; } }