|
4 | 4 | using System;
|
5 | 5 | using System.Collections.Generic;
|
6 | 6 | using System.Diagnostics;
|
7 |
| -using System.Numerics; |
8 | 7 | using System.Runtime;
|
9 | 8 | using System.Runtime.CompilerServices;
|
10 | 9 |
|
11 | 10 | namespace System.Reflection
|
12 | 11 | {
|
13 | 12 | [ReflectionBlocked]
|
14 |
| - public abstract class EnumInfo |
| 13 | + public sealed class EnumInfo |
15 | 14 | {
|
16 |
| - private protected EnumInfo(Type underlyingType, string[] names, bool isFlags) |
| 15 | + public EnumInfo(Type underlyingType, object[] rawValues, string[] names, bool isFlags) |
17 | 16 | {
|
| 17 | + Debug.Assert(rawValues.Length == names.Length); |
| 18 | + |
18 | 19 | UnderlyingType = underlyingType;
|
19 |
| - Names = names; |
20 |
| - HasFlagsAttribute = isFlags; |
21 |
| - } |
22 | 20 |
|
23 |
| - internal Type UnderlyingType { get; } |
24 |
| - internal string[] Names { get; } |
25 |
| - internal bool HasFlagsAttribute { get; } |
26 |
| - } |
| 21 | + int numValues = rawValues.Length; |
| 22 | + ulong[] values = new ulong[numValues]; |
| 23 | + for (int i = 0; i < numValues; i++) |
| 24 | + { |
| 25 | + object rawValue = rawValues[i]; |
27 | 26 |
|
28 |
| - [ReflectionBlocked] |
29 |
| - public sealed class EnumInfo<TUnderlyingValue> : EnumInfo |
30 |
| - where TUnderlyingValue : struct, INumber<TUnderlyingValue> |
31 |
| - { |
32 |
| - public EnumInfo(Type underlyingType, TUnderlyingValue[] values, string[] names, bool isFlags) : |
33 |
| - base(underlyingType, names, isFlags) |
34 |
| - { |
35 |
| - Debug.Assert(values.Length == names.Length); |
| 27 | + ulong rawUnboxedValue; |
| 28 | + if (rawValue is ulong) |
| 29 | + { |
| 30 | + rawUnboxedValue = (ulong)rawValue; |
| 31 | + } |
| 32 | + else |
| 33 | + { |
| 34 | + // This conversion is this way for compatibility: do a value-preseving cast to long - then store (and compare) as ulong. This affects |
| 35 | + // the order in which the Enum apis return names and values. |
| 36 | + rawUnboxedValue = (ulong)(((IConvertible)rawValue).ToInt64(null)); |
| 37 | + } |
| 38 | + values[i] = rawUnboxedValue; |
| 39 | + } |
36 | 40 |
|
37 |
| - Array.Sort(keys: values, items: names); |
| 41 | + // Need to sort the `names` and `rawValues` arrays according to the `values` array |
| 42 | + ulong[] valuesCopy = (ulong[])values.Clone(); |
| 43 | + Array.Sort(keys: valuesCopy, items: rawValues, comparer: Comparer<ulong>.Default); |
| 44 | + Array.Sort(keys: values, items: names, comparer: Comparer<ulong>.Default); |
38 | 45 |
|
| 46 | + Names = names; |
39 | 47 | Values = values;
|
40 |
| - ValuesAreSequentialFromZero = Enum.AreSequentialFromZero(values); |
| 48 | + |
| 49 | + // Create the unboxed version of values for the Values property to return. (We didn't do this earlier because |
| 50 | + // declaring "rawValues" as "Array" would prevent us from using the generic overload of Array.Sort()). |
| 51 | + // |
| 52 | + // The array element type is the underlying type, not the enum type. (The enum type could be an open generic.) |
| 53 | + ValuesAsUnderlyingType = Type.GetTypeCode(UnderlyingType) switch |
| 54 | + { |
| 55 | + TypeCode.Byte => new byte[numValues], |
| 56 | + TypeCode.SByte => new sbyte[numValues], |
| 57 | + TypeCode.UInt16 => new ushort[numValues], |
| 58 | + TypeCode.Int16 => new short[numValues], |
| 59 | + TypeCode.UInt32 => new uint[numValues], |
| 60 | + TypeCode.Int32 => new int[numValues], |
| 61 | + TypeCode.UInt64 => new ulong[numValues], |
| 62 | + TypeCode.Int64 => new long[numValues], |
| 63 | + _ => throw new NotSupportedException(), |
| 64 | + }; |
| 65 | + Array.Copy(rawValues, ValuesAsUnderlyingType, numValues); |
| 66 | + |
| 67 | + HasFlagsAttribute = isFlags; |
| 68 | + |
| 69 | + ValuesAreSequentialFromZero = true; |
| 70 | + for (int i = 0; i < values.Length; i++) |
| 71 | + { |
| 72 | + if (values[i] != (ulong)i) |
| 73 | + { |
| 74 | + ValuesAreSequentialFromZero = false; |
| 75 | + break; |
| 76 | + } |
| 77 | + } |
41 | 78 | }
|
42 | 79 |
|
43 |
| - internal TUnderlyingValue[] Values { get; } |
| 80 | + internal Type UnderlyingType { get; } |
| 81 | + internal string[] Names { get; } |
| 82 | + internal ulong[] Values { get; } |
| 83 | + internal Array ValuesAsUnderlyingType { get; } |
| 84 | + internal bool HasFlagsAttribute { get; } |
44 | 85 | internal bool ValuesAreSequentialFromZero { get; }
|
45 |
| - |
46 |
| - public TUnderlyingValue[] CloneValues() => |
47 |
| - new ReadOnlySpan<TUnderlyingValue>(Values).ToArray(); |
48 | 86 | }
|
49 | 87 | }
|
0 commit comments