From f2a57e6c62e59e1308ac0f3ffebb51d454860efb Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Fri, 29 Jul 2022 04:19:42 -0700 Subject: [PATCH 01/18] Implement new API GetEnumValuesAsUnderlyingType --- .../src/System/RuntimeType.cs | 8 +++ .../System.Private.CoreLib/src/System/Enum.cs | 9 +++ .../src/System/RuntimeType.cs | 23 +++++- .../System.Private.CoreLib/src/System/Type.cs | 13 ++++ .../Reflection/TypeLoading/Types/RoType.cs | 30 ++++++++ .../System.Reflection/tests/TypeInfoTests.cs | 18 +++++ .../System.Runtime/ref/System.Runtime.cs | 3 + .../System.Runtime/tests/System/EnumTests.cs | 70 +++++++++++++++++++ .../SmokeTests/Reflection/Reflection.cs | 6 ++ 9 files changed, 179 insertions(+), 1 deletion(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs index cce84ae6ed1f8..719424c6faefd 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs @@ -111,6 +111,14 @@ public sealed override Array GetEnumValues() return result; } + public sealed override Array GetEnumValuesAsUnderlyingType() + { + if (!IsActualEnum) + throw new ArgumentException(SR.Arg_MustBeEnum, "enumType"); + + return (Array)Enum.GetEnumInfo(this).ValuesAsUnderlyingType.Clone(); + } + internal bool IsActualEnum => TryGetEEType(out EETypePtr eeType) && eeType.IsEnum; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index e3f994148b55d..6cefc44f61edc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -322,6 +322,15 @@ public static Array GetValues(Type enumType) return enumType.GetEnumValues(); } + public static Array GetValuesAsUnderlyingType() where TEnum : struct, Enum => + GetValuesAsUnderlyingType(typeof(TEnum)); + + public static Array GetValuesAsUnderlyingType(Type enumType) + { + ArgumentNullException.ThrowIfNull(enumType); + return enumType.GetEnumValuesAsUnderlyingType(); + } + [Intrinsic] public bool HasFlag(Enum flag) { diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 0182163de6aef..4f1c935dab313 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -7,6 +7,8 @@ using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Internal; namespace System { @@ -124,7 +126,7 @@ public override Array GetEnumValues() if (!IsActualEnum) throw new ArgumentException(SR.Arg_MustBeEnum, "enumType"); - // Get all of the values + // Get all of tkhe values ulong[] values = Enum.InternalGetValues(this); // Create a generic Array @@ -139,6 +141,25 @@ public override Array GetEnumValues() return ret; } + public override Array GetEnumValuesAsUnderlyingType() + { + if (!IsActualEnum) + throw new ArgumentException(SR.Arg_MustBeEnum, "enumType"); + + // Get all of the values + ulong[] values = Enum.InternalGetValues(this); + + Array ret = Array.CreateInstance(Enum.InternalGetUnderlyingType(this), values.Length); + + for (int i = 0; i < values.Length; i++) + { + object val = Enum.ToObject(this, values[i]); + ret.SetValue(val, i); + } + + return ret; + } + public override Type GetEnumUnderlyingType() { if (!IsActualEnum) diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index 4907875d591c5..d06309ffefbfa 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -526,6 +526,19 @@ public virtual Array GetEnumValues() throw NotImplemented.ByDesign; } + [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", + Justification = "The runtime overrides this method with AOT compatible implementation")] + public virtual Array GetEnumValuesAsUnderlyingType() + { + if (!IsEnum) + throw new ArgumentException(SR.Arg_MustBeEnum, "enumType"); + + Array enumValues = GetEnumValues(); + Array ret = Array.CreateInstance(GetEnumUnderlyingType(), enumValues.Length); + Array.Copy(enumValues, ret, enumValues.Length); + return ret; + } + [RequiresDynamicCode("The code for an array of the specified type might not be available.")] public virtual Type MakeArrayType() => throw new NotSupportedException(); [RequiresDynamicCode("The code for an array of the specified type might not be available.")] diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs index 57341e16a36d3..9f37528acc46b 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs @@ -288,6 +288,36 @@ public sealed override Type MakeArrayType(int rank) private volatile RoType? _lazyUnderlyingEnumType; public sealed override Array GetEnumValues() => throw new InvalidOperationException(SR.Arg_InvalidOperation_Reflection); + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2085:UnrecognizedReflectionPattern", + Justification = "Enum Types are not trimmed.")] + public override Array GetEnumValuesAsUnderlyingType() + { + if (!IsEnum) + throw new ArgumentException(SR.Arg_MustBeEnum, "enumType"); + + FieldInfo[] enumFields = this.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + int numValues = enumFields.Length; + Array ret = Type.GetTypeCode(GetEnumUnderlyingType()) switch + { + TypeCode.Byte => new byte[numValues], + TypeCode.SByte => new sbyte[numValues], + TypeCode.UInt16 => new ushort[numValues], + TypeCode.Int16 => new short[numValues], + TypeCode.UInt32 => new uint[numValues], + TypeCode.Int32 => new int[numValues], + TypeCode.UInt64 => new ulong[numValues], + TypeCode.Int64 => new long[numValues], + _ => throw new NotSupportedException(), + }; + + for (int i = 0; i < numValues; i++) + { + ret.SetValue(enumFields[i].GetRawConstantValue(), i); + } + + return ret; + } + // No trust environment to apply these to. public sealed override bool IsSecurityCritical => throw new InvalidOperationException(SR.InvalidOperation_IsSecurity); public sealed override bool IsSecuritySafeCritical => throw new InvalidOperationException(SR.InvalidOperation_IsSecurity); diff --git a/src/libraries/System.Reflection/tests/TypeInfoTests.cs b/src/libraries/System.Reflection/tests/TypeInfoTests.cs index 6b553ef4d430b..e17625c5a7214 100644 --- a/src/libraries/System.Reflection/tests/TypeInfoTests.cs +++ b/src/libraries/System.Reflection/tests/TypeInfoTests.cs @@ -457,6 +457,24 @@ private static void GetEnumValues(Type enumType, Array expected) Assert.Equal(expected, enumType.GetTypeInfo().GetEnumValues()); } + [Fact] + public static void GetEnumValuesAsUnderlyingType_Int() + { + GetEnumValuesAsUnderlyingType(typeof(IntEnum), new int[] { 1, 2, 10, 18, 45 }); + } + + [Fact] + public static void GetEnumValuesAsUnderlyingType_UInt() + { + GetEnumValues(typeof(UIntEnum), new uint[] { 1, 10 }); + } + + private static void GetEnumValuesAsUnderlyingType(Type enumType, Array expected) + { + Assert.Equal(expected, enumType.GetTypeInfo().GetEnumValuesAsUnderlyingType()); + } + + [Fact] public void GetEnumValues_TypeNotEnum_ThrowsArgumentException() { diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 4449a3fd35677..659c1b7998933 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -2315,6 +2315,8 @@ protected Enum() { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetValues overload instead.")] public static System.Array GetValues(System.Type enumType) { throw null; } public static TEnum[] GetValues() where TEnum : struct, System.Enum { throw null; } + public static System.Array GetValuesAsUnderlyingType(System.Type enumType) { throw null; } + public static System.Array GetValuesAsUnderlyingType() where TEnum : struct, System.Enum { throw null; } public bool HasFlag(System.Enum flag) { throw null; } public static bool IsDefined(System.Type enumType, object value) { throw null; } public static bool IsDefined(TEnum value) where TEnum : struct, System.Enum { throw null; } @@ -5862,6 +5864,7 @@ protected Type() { } public virtual System.Type GetEnumUnderlyingType() { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use Enum.GetValues instead.")] public virtual System.Array GetEnumValues() { throw null; } + public virtual System.Array GetEnumValuesAsUnderlyingType() { throw null; } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicEvents)] public System.Reflection.EventInfo? GetEvent(string name) { throw null; } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicEvents | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicEvents)] diff --git a/src/libraries/System.Runtime/tests/System/EnumTests.cs b/src/libraries/System.Runtime/tests/System/EnumTests.cs index 245840ee34879..a243e6c7c8bff 100644 --- a/src/libraries/System.Runtime/tests/System/EnumTests.cs +++ b/src/libraries/System.Runtime/tests/System/EnumTests.cs @@ -1589,6 +1589,76 @@ public static void GetValues_NullEnumType_ThrowsArgumentNullException() AssertExtensions.Throws("enumType", () => Enum.GetValues(null)); } + [Fact] + public void GetValuesAsUnderlyingType_InvokeSByteEnum_ReturnsExpected() + { + Array expected = new sbyte[] { 1, 2, sbyte.MaxValue, sbyte.MinValue }; + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType(typeof(SByteEnum))); + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType()); + } + + [Fact] + public void GetValuesAsUnderlyingType_InvokeByteEnum_ReturnsExpected() + { + Array expected = new byte[] { byte.MinValue, 1, 2, byte.MaxValue }; + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType(typeof(ByteEnum))); + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType()); + } + + [Fact] + public void GetValuesAsUnderlyingType_InvokeInt16Enum_ReturnsExpected() + { + Array expected = new short[] { 1, 2, short.MaxValue, short.MinValue }; + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType(typeof(Int16Enum))); + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType()); + } + + [Fact] + public void GetValuesAsUnderlyingType_InvokeUInt16Enum_ReturnsExpected() + { + Array expected = new ushort[] { ushort.MinValue, 1, 2, ushort.MaxValue }; + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType(typeof(UInt16Enum))); + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType()); + } + + [Fact] + public void GetValuesAsUnderlyingType_InvokeInt32Enum_ReturnsExpected() + { + Array expected = new int[] { 1, 2, int.MaxValue, int.MinValue }; + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType(typeof(Int32Enum))); + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType()); + } + + [Fact] + public void GetValuesAsUnderlyingType_InvokeUInt32Enum_ReturnsExpected() + { + Array expected = new uint[] { uint.MinValue, 1, 2, uint.MaxValue }; + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType(typeof(UInt32Enum))); + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType()); + } + + [Fact] + public void GetValuesAsUnderlyingType_InvokeInt64Enum_ReturnsExpected() + { + Array expected = new long[] { 1, 2, long.MaxValue, long.MinValue }; + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType(typeof(Int64Enum))); + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType()); + } + + [Fact] + public void GetValuesAsUnderlyingType_InvokeUInt64Enum_ReturnsExpected() + { + Array expected = new ulong[] { ulong.MinValue, 1, 2, ulong.MaxValue }; + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType(typeof(UInt64Enum))); + Assert.Equal(expected, Enum.GetValuesAsUnderlyingType()); + } + + [Fact] + public static void GetValuesAsUnderlyingType_NullEnumType_ThrowsArgumentNullException() + { + AssertExtensions.Throws("enumType", () => Enum.GetValuesAsUnderlyingType(null)); + } + [Theory] [InlineData(typeof(object))] [InlineData(typeof(int))] diff --git a/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs b/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs index 8dc2c6e88a768..7d19984d50222 100644 --- a/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs +++ b/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs @@ -1434,6 +1434,12 @@ public static void Run() throw new Exception("GetValues"); } + Console.WriteLine("Enum.GetEnumValuesAsUnderlyingType"); + { + if (Enum.GetEnumValuesAsUnderlyingType(typeof(Mine)) is not int[]) + throw new Exception("GetEnumValuesAsUnderlyingType"); + } + Console.WriteLine("Pattern in LINQ expressions"); { Type objType = typeof(object); From 95d423f37f7104c6e9bc03d3860579d72b17125e Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Fri, 29 Jul 2022 09:25:05 -0700 Subject: [PATCH 02/18] Update src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs Co-authored-by: Jan Kotas --- src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 4f1c935dab313..274e5adfaa849 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -126,7 +126,7 @@ public override Array GetEnumValues() if (!IsActualEnum) throw new ArgumentException(SR.Arg_MustBeEnum, "enumType"); - // Get all of tkhe values + // Get all of the values ulong[] values = Enum.InternalGetValues(this); // Create a generic Array From 5a348ca0918b868cfa1093b37f12b4f3e42f0d38 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Sat, 30 Jul 2022 06:41:37 -0700 Subject: [PATCH 03/18] FB --- .../System/ComponentModel/EnumConverter.cs | 5 +++-- .../System.Private.CoreLib/src/System/Enum.cs | 2 +- .../src/System/Reflection/SignatureType.cs | 2 +- .../src/System/RuntimeType.cs | 2 +- .../System.Private.CoreLib/src/System/Type.cs | 2 +- .../Reflection/TypeLoading/Types/RoType.cs | 2 ++ .../src/SampleMetadata/SampleMetadata.cs | 3 +++ .../tests/src/Tests/Type/TypeTests.cs | 22 +++++++++++++++++++ .../System.Runtime/ref/System.Runtime.cs | 4 ++-- 9 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/EnumConverter.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/EnumConverter.cs index 81e10e504d83e..d7637ce927804 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/EnumConverter.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/EnumConverter.cs @@ -171,11 +171,12 @@ private static long GetEnumValue(bool isUnderlyingTypeUInt64, Enum enumVal, Cult bool isUnderlyingTypeUInt64 = Enum.GetUnderlyingType(EnumType) == typeof(ulong); List flagValues = new List(); - Array objValues = Enum.GetValues(EnumType); + Array objValues = Enum.GetValuesAsUnderlyingType(EnumType); long[] ulValues = new long[objValues.Length]; for (int idx = 0; idx < objValues.Length; idx++) { - ulValues[idx] = GetEnumValue(isUnderlyingTypeUInt64, (Enum)objValues.GetValue(idx)!, culture); + ulValues[idx] = isUnderlyingTypeUInt64 ? unchecked((long)Convert.ToUInt64(objValues.GetValue(idx), culture)) : + Convert.ToInt64(objValues.GetValue(idx), culture); } long longValue = GetEnumValue(isUnderlyingTypeUInt64, (Enum)value, culture); diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index 6cefc44f61edc..11e8a1b1e0ebb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -315,7 +315,7 @@ public static TEnum[] GetValues() where TEnum : struct, Enum => (TEnum[])GetValues(typeof(TEnum)); #endif - [RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetValues overload instead.")] + [RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetValues overload or the GetValuesAsUnderlyingType method instead.")] public static Array GetValues(Type enumType) { ArgumentNullException.ThrowIfNull(enumType); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureType.cs index 1d7251ed5df2e..56d9d454e9717 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureType.cs @@ -99,7 +99,7 @@ public sealed override Type MakeArrayType(int rank) public sealed override string GetEnumName(object value) => throw new NotSupportedException(SR.NotSupported_SignatureType); public sealed override string[] GetEnumNames() => throw new NotSupportedException(SR.NotSupported_SignatureType); public sealed override Type GetEnumUnderlyingType() => throw new NotSupportedException(SR.NotSupported_SignatureType); - [RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use Enum.GetValues instead.")] + [RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetEnumValues overload or the GetEnumValuesAsUnderlyingType method instead.")] public sealed override Array GetEnumValues() => throw new NotSupportedException(SR.NotSupported_SignatureType); public sealed override Guid GUID => throw new NotSupportedException(SR.NotSupported_SignatureType); protected sealed override TypeCode GetTypeCodeImpl() => throw new NotSupportedException(SR.NotSupported_SignatureType); diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 274e5adfaa849..385c104bd1c1e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -120,7 +120,7 @@ public override string[] GetEnumNames() return new ReadOnlySpan(ret).ToArray(); } - [RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetValues overload instead.")] + [RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetEnumValues overload or the GetEnumValuesAsUnderlyingType method instead.")] public override Array GetEnumValues() { if (!IsActualEnum) diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index d06309ffefbfa..6145218dbc73a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -515,7 +515,7 @@ public virtual Type GetEnumUnderlyingType() return fields[0].FieldType; } - [RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use Enum.GetValues instead.")] + [RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetEnumValues overload or the GetEnumValuesAsUnderlyingType method instead.")] public virtual Array GetEnumValues() { if (!IsEnum) diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs index 9f37528acc46b..6e55577bc836b 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs @@ -288,6 +288,7 @@ public sealed override Type MakeArrayType(int rank) private volatile RoType? _lazyUnderlyingEnumType; public sealed override Array GetEnumValues() => throw new InvalidOperationException(SR.Arg_InvalidOperation_Reflection); +#if NET7_0_OR_GREATER [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2085:UnrecognizedReflectionPattern", Justification = "Enum Types are not trimmed.")] public override Array GetEnumValuesAsUnderlyingType() @@ -317,6 +318,7 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } +#endif // No trust environment to apply these to. public sealed override bool IsSecurityCritical => throw new InvalidOperationException(SR.InvalidOperation_IsSecurity); diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/SampleMetadata/SampleMetadata.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/SampleMetadata/SampleMetadata.cs index b60f7cd86d897..9f01b3b5efcb2 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/SampleMetadata/SampleMetadata.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/SampleMetadata/SampleMetadata.cs @@ -84,6 +84,9 @@ public enum EI4 : int { } public enum EU8 : ulong { } public enum EI8 : long { } + public enum E_2_I4 : int { min=int.MinValue, zero=0, one=1, max=int.MaxValue} + public enum E_2_U4 : uint { min = uint.MinValue, zero = 0, one = 1, max = uint.MaxValue } + public class GenericEnumContainer { public enum GenericEnum : short { } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs index c0292e2999957..6676261b5fe51 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs @@ -365,6 +365,28 @@ public static IEnumerable GetEnumUnderlyingTypeData } } + [Fact] + public static void GetEnumValuesAsUnderlyingType() + { + var intEnumType = typeof(E_2_I4).Project(); + int[] expectedIntValues = { int.MinValue, 0, 1, int.MaxValue }; + Array intArr = intEnumType.GetEnumValuesAsUnderlyingType(); + for (int i = 0; i < intArr.Length; i++) + { + Assert.Equal(expectedIntValues[i], intArr.GetValue(i)); + Assert.Equal(Type.GetTypeCode(expectedIntValues[i].GetType()), Type.GetTypeCode(intArr.GetValue(i).GetType())); + } + + var uintEnumType = typeof(E_2_U4).Project(); + uint[] expectesUIntValues = { uint.MinValue, 0, 1, uint.MaxValue }; + Array uintArr = uintEnumType.GetEnumValuesAsUnderlyingType(); + for (int i = 0; i < uintArr.Length; i++) + { + Assert.Equal(expectesUIntValues[i], uintArr.GetValue(i)); + Assert.Equal(Type.GetTypeCode(expectesUIntValues[i].GetType()), Type.GetTypeCode(uintArr.GetValue(i).GetType())); + } + } + [Theory] [MemberData(nameof(GetTypeCodeTheoryData))] public static void GettypeCode(TypeWrapper tw, TypeCode expectedTypeCode) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 659c1b7998933..a4f5c4e1e3053 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -2312,7 +2312,7 @@ protected Enum() { } public static string[] GetNames() where TEnum: struct, System.Enum { throw null; } public System.TypeCode GetTypeCode() { throw null; } public static System.Type GetUnderlyingType(System.Type enumType) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetValues overload instead.")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetValues overload or the GetValuesAsUnderlyingType method instead.")] public static System.Array GetValues(System.Type enumType) { throw null; } public static TEnum[] GetValues() where TEnum : struct, System.Enum { throw null; } public static System.Array GetValuesAsUnderlyingType(System.Type enumType) { throw null; } @@ -5862,7 +5862,7 @@ protected Type() { } public virtual string? GetEnumName(object value) { throw null; } public virtual string[] GetEnumNames() { throw null; } public virtual System.Type GetEnumUnderlyingType() { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use Enum.GetValues instead.")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetEnumValues overload or the GetEnumValuesAsUnderlyingType method instead.")] public virtual System.Array GetEnumValues() { throw null; } public virtual System.Array GetEnumValuesAsUnderlyingType() { throw null; } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicEvents)] From d77c10e94b5a10e2b06223a4b66dc32145f9a3e9 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Sat, 30 Jul 2022 09:00:10 -0700 Subject: [PATCH 04/18] Update src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs Co-authored-by: Jan Kotas --- src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs b/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs index 7d19984d50222..94b6ce8470aa7 100644 --- a/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs +++ b/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs @@ -1436,7 +1436,7 @@ public static void Run() Console.WriteLine("Enum.GetEnumValuesAsUnderlyingType"); { - if (Enum.GetEnumValuesAsUnderlyingType(typeof(Mine)) is not int[]) + if (Enum.GetEnumValuesAsUnderlyingType(typeof(Mine)).GetType() != typeof(int[])) throw new Exception("GetEnumValuesAsUnderlyingType"); } From e31e0dc87a9fe4870336ea30ced1c9c300de381e Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Sat, 30 Jul 2022 12:29:25 -0700 Subject: [PATCH 05/18] FB2 --- .../src/System/ComponentModel/EnumConverter.cs | 9 ++++----- .../System.Private.CoreLib/src/System/RuntimeType.cs | 2 -- src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/EnumConverter.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/EnumConverter.cs index d7637ce927804..5dcc263e0d0c0 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/EnumConverter.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/EnumConverter.cs @@ -62,7 +62,7 @@ public override bool CanConvertTo(ITypeDescriptorContext? context, [NotNullWhen( /// protected virtual IComparer Comparer => InvariantComparer.Default; - private static long GetEnumValue(bool isUnderlyingTypeUInt64, Enum enumVal, CultureInfo? culture) + private static long GetEnumValue(bool isUnderlyingTypeUInt64, object enumVal, CultureInfo? culture) { return isUnderlyingTypeUInt64 ? unchecked((long)Convert.ToUInt64(enumVal, culture)) : @@ -85,7 +85,7 @@ private static long GetEnumValue(bool isUnderlyingTypeUInt64, Enum enumVal, Cult string[] values = strValue.Split(','); foreach (string v in values) { - convertedValue |= GetEnumValue(isUnderlyingTypeUInt64, (Enum)Enum.Parse(EnumType, v, true), culture); + convertedValue |= GetEnumValue(isUnderlyingTypeUInt64, Enum.Parse(EnumType, v, true), culture); } return Enum.ToObject(EnumType, convertedValue); } @@ -175,11 +175,10 @@ private static long GetEnumValue(bool isUnderlyingTypeUInt64, Enum enumVal, Cult long[] ulValues = new long[objValues.Length]; for (int idx = 0; idx < objValues.Length; idx++) { - ulValues[idx] = isUnderlyingTypeUInt64 ? unchecked((long)Convert.ToUInt64(objValues.GetValue(idx), culture)) : - Convert.ToInt64(objValues.GetValue(idx), culture); + ulValues[idx] = GetEnumValue(isUnderlyingTypeUInt64, objValues.GetValue(idx)!, culture); } - long longValue = GetEnumValue(isUnderlyingTypeUInt64, (Enum)value, culture); + long longValue = GetEnumValue(isUnderlyingTypeUInt64, value, culture); bool valueFound = true; while (valueFound) { diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 385c104bd1c1e..7f34baa014f00 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -7,8 +7,6 @@ using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Internal; namespace System { diff --git a/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs b/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs index 94b6ce8470aa7..b01cd2a208bea 100644 --- a/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs +++ b/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs @@ -1436,7 +1436,7 @@ public static void Run() Console.WriteLine("Enum.GetEnumValuesAsUnderlyingType"); { - if (Enum.GetEnumValuesAsUnderlyingType(typeof(Mine)).GetType() != typeof(int[])) + if (Enum.GetValuesAsUnderlyingType(typeof(Mine)).GetType() != typeof(int[])) throw new Exception("GetEnumValuesAsUnderlyingType"); } From f62047f2db7150849cef19fa7a213efd24391a99 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sat, 30 Jul 2022 12:53:38 -0700 Subject: [PATCH 06/18] Apply suggestions from code review --- src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs b/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs index b01cd2a208bea..676f4e457ed42 100644 --- a/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs +++ b/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs @@ -1434,10 +1434,10 @@ public static void Run() throw new Exception("GetValues"); } - Console.WriteLine("Enum.GetEnumValuesAsUnderlyingType"); + Console.WriteLine("Enum.GetValuesAsUnderlyingType"); { if (Enum.GetValuesAsUnderlyingType(typeof(Mine)).GetType() != typeof(int[])) - throw new Exception("GetEnumValuesAsUnderlyingType"); + throw new Exception("Enum.GetValuesAsUnderlyingType"); } Console.WriteLine("Pattern in LINQ expressions"); From f5e5ccfdf663a2c41cabf439071725c0d12c008b Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sat, 30 Jul 2022 12:59:02 -0700 Subject: [PATCH 07/18] Update src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs --- .../src/System/Reflection/TypeLoading/Types/RoType.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs index 6e55577bc836b..e57cafb5ba872 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs @@ -296,7 +296,7 @@ public override Array GetEnumValuesAsUnderlyingType() if (!IsEnum) throw new ArgumentException(SR.Arg_MustBeEnum, "enumType"); - FieldInfo[] enumFields = this.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + FieldInfo[] enumFields = GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); int numValues = enumFields.Length; Array ret = Type.GetTypeCode(GetEnumUnderlyingType()) switch { From e805d1743e096cf5e0b6a432d1931da9a100ff02 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sat, 30 Jul 2022 14:28:50 -0700 Subject: [PATCH 08/18] Update src/libraries/System.Reflection/tests/TypeInfoTests.cs --- src/libraries/System.Reflection/tests/TypeInfoTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Reflection/tests/TypeInfoTests.cs b/src/libraries/System.Reflection/tests/TypeInfoTests.cs index e17625c5a7214..3e6cd0deeffbc 100644 --- a/src/libraries/System.Reflection/tests/TypeInfoTests.cs +++ b/src/libraries/System.Reflection/tests/TypeInfoTests.cs @@ -466,7 +466,7 @@ public static void GetEnumValuesAsUnderlyingType_Int() [Fact] public static void GetEnumValuesAsUnderlyingType_UInt() { - GetEnumValues(typeof(UIntEnum), new uint[] { 1, 10 }); + GetEnumValuesAsUnderlyingType(typeof(UIntEnum), new uint[] { 1, 10 }); } private static void GetEnumValuesAsUnderlyingType(Type enumType, Array expected) From 12a14fdc6b1a8758025e9dd9acd60e3286d5c851 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sat, 30 Jul 2022 18:03:59 -0700 Subject: [PATCH 09/18] Update src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs --- .../tests/src/Tests/Type/TypeTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs index 6676261b5fe51..03611db20825a 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs @@ -365,6 +365,7 @@ public static IEnumerable GetEnumUnderlyingTypeData } } +#if NET7_0_OR_GREATER [Fact] public static void GetEnumValuesAsUnderlyingType() { @@ -386,6 +387,7 @@ public static void GetEnumValuesAsUnderlyingType() Assert.Equal(Type.GetTypeCode(expectesUIntValues[i].GetType()), Type.GetTypeCode(uintArr.GetValue(i).GetType())); } } +#endif [Theory] [MemberData(nameof(GetTypeCodeTheoryData))] From ab863162ad94e9dfe70dff6dae4f81da8406e9c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Mon, 1 Aug 2022 11:32:58 +0900 Subject: [PATCH 10/18] Update src/libraries/System.Private.CoreLib/src/System/Type.cs Co-authored-by: Jan Kotas --- .../System.Private.CoreLib/src/System/Type.cs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index 6145218dbc73a..7284f8bcf05c7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -526,18 +526,7 @@ public virtual Array GetEnumValues() throw NotImplemented.ByDesign; } - [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", - Justification = "The runtime overrides this method with AOT compatible implementation")] - public virtual Array GetEnumValuesAsUnderlyingType() - { - if (!IsEnum) - throw new ArgumentException(SR.Arg_MustBeEnum, "enumType"); - - Array enumValues = GetEnumValues(); - Array ret = Array.CreateInstance(GetEnumUnderlyingType(), enumValues.Length); - Array.Copy(enumValues, ret, enumValues.Length); - return ret; - } + public virtual Array GetEnumValuesAsUnderlyingType() => throw new NotSupportedException(SR.NotSupported_SubclassOverride); [RequiresDynamicCode("The code for an array of the specified type might not be available.")] public virtual Type MakeArrayType() => throw new NotSupportedException(); From 6a7d6c1e76a804f1dd7749d3e8bc59eec0878e73 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Mon, 1 Aug 2022 08:30:41 -0700 Subject: [PATCH 11/18] Update src/libraries/System.Private.CoreLib/src/System/Enum.cs Co-authored-by: Stephen Toub --- src/libraries/System.Private.CoreLib/src/System/Enum.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index 11e8a1b1e0ebb..d5ea8feb83f42 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -323,7 +323,7 @@ public static Array GetValues(Type enumType) } public static Array GetValuesAsUnderlyingType() where TEnum : struct, Enum => - GetValuesAsUnderlyingType(typeof(TEnum)); + typeof(TEnum).GetEnumValuesAsUnderlyingType(); public static Array GetValuesAsUnderlyingType(Type enumType) { From f382a5fb24d44b0a45156509de12282863691a33 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Mon, 1 Aug 2022 10:36:11 -0700 Subject: [PATCH 12/18] FB3 --- .../System.Private.CoreLib/src/System/Enum.cs | 21 ++++ .../src/System/RuntimeType.cs | 95 +++++++++++++++++-- .../System.Private.CoreLib/src/System/Type.cs | 11 +++ 3 files changed, 120 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index d5ea8feb83f42..623efb266de6f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -322,9 +322,30 @@ public static Array GetValues(Type enumType) return enumType.GetEnumValues(); } + /// + /// Gets an array of values of the underlying type of the Enum. + /// + /// Enum type + /// /// + /// This method can be used to get enum values when creating an Array of Enum is challenging + /// For example, reflection-only context or on a platform where runtime codegen is not available. + /// + /// Array of values containing the underlying type of the Enum public static Array GetValuesAsUnderlyingType() where TEnum : struct, Enum => typeof(TEnum).GetEnumValuesAsUnderlyingType(); + /// + /// Gets an array of values of the underlying type of the Enum. + /// + /// Enum type + /// + /// This method can be used to get enum values when creating an Array of Enum is challenging + /// For example, in reflection-only context or on a platform where runtime codegen is not available. + /// + /// Array of values containing the underlying type of the Enum + /// + /// Thrown when the enum type is null + /// public static Array GetValuesAsUnderlyingType(Type enumType) { ArgumentNullException.ThrowIfNull(enumType); diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 7f34baa014f00..2e0cd2b9b6243 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -139,6 +139,17 @@ public override Array GetEnumValues() return ret; } + /// + /// Gets an array of values of the underlying type of the Enum. + /// + /// + /// This method can be used to get enum values when creating an Array of Enum is challenging + /// For example, in reflection-only context or on a platform where runtime codegen is not available. + /// + /// Array of values containing the underlying type of the Enum + /// + /// Thrown when the type is not Enum + /// public override Array GetEnumValuesAsUnderlyingType() { if (!IsActualEnum) @@ -147,15 +158,85 @@ public override Array GetEnumValuesAsUnderlyingType() // Get all of the values ulong[] values = Enum.InternalGetValues(this); - Array ret = Array.CreateInstance(Enum.InternalGetUnderlyingType(this), values.Length); - - for (int i = 0; i < values.Length; i++) + switch (RuntimeTypeHandle.GetCorElementType(Enum.InternalGetUnderlyingType(this))) { - object val = Enum.ToObject(this, values[i]); - ret.SetValue(val, i); - } + case CorElementType.ELEMENT_TYPE_U1: + { + var ret = new byte[values.Length]; + for (int i = 0; i < values.Length; i++) + { + ret[i] = (byte)values[i]; + } + return ret; + } - return ret; + case CorElementType.ELEMENT_TYPE_U2: + { + var ret = new ushort[values.Length]; + for (int i = 0; i < values.Length; i++) + { + ret[i] = (ushort)values[i]; + } + return ret; + } + + case CorElementType.ELEMENT_TYPE_U4: + { + var ret = new uint[values.Length]; + for (int i = 0; i < values.Length; i++) + { + ret[i] = (uint)values[i]; + } + return ret; + } + + case CorElementType.ELEMENT_TYPE_U8: + { + return (Array)values.Clone(); + } + + case CorElementType.ELEMENT_TYPE_I1: + { + var ret = new sbyte[values.Length]; + for (int i = 0; i < values.Length; i++) + { + ret[i] = (sbyte)values[i]; + } + return ret; + } + + case CorElementType.ELEMENT_TYPE_I2: + { + var ret = new short[values.Length]; + for (int i = 0; i < values.Length; i++) + { + ret[i] = (short)values[i]; + } + return ret; + } + + case CorElementType.ELEMENT_TYPE_I4: + { + var ret = new int[values.Length]; + for (int i = 0; i < values.Length; i++) + { + ret[i] = (int)values[i]; + } + return ret; + } + + case CorElementType.ELEMENT_TYPE_I8: + { + var ret = new long[values.Length]; + for (int i = 0; i < values.Length; i++) + { + ret[i] = (long)values[i]; + } + return ret; + } + default: + throw new NotImplementedException("Not Implemented"); + } } public override Type GetEnumUnderlyingType() diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index 7284f8bcf05c7..f7210aa072ca2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -526,6 +526,17 @@ public virtual Array GetEnumValues() throw NotImplemented.ByDesign; } + /// + /// Gets an array of values of the underlying type of the Enum. + /// + /// + /// This method can be used to get enum values when creating an Array of Enum is challenging + /// For example, in reflection-only context or on a platform where runtime codegen is not available. + /// + /// Array of values containing the underlying type of the Enum + /// + /// Thrown when the type is not Enum + /// public virtual Array GetEnumValuesAsUnderlyingType() => throw new NotSupportedException(SR.NotSupported_SubclassOverride); [RequiresDynamicCode("The code for an array of the specified type might not be available.")] From 0e980c083572f8c0d59e0f65d44c58afc01f8a65 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Mon, 1 Aug 2022 13:01:32 -0700 Subject: [PATCH 13/18] Update src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs Co-authored-by: Jan Kotas --- src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 2e0cd2b9b6243..23f452f352bb9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -158,7 +158,7 @@ public override Array GetEnumValuesAsUnderlyingType() // Get all of the values ulong[] values = Enum.InternalGetValues(this); - switch (RuntimeTypeHandle.GetCorElementType(Enum.InternalGetUnderlyingType(this))) + switch (RuntimeTypeHandle.GetCorElementType(this)) { case CorElementType.ELEMENT_TYPE_U1: { From 7050f94c3a3b3116d45502ae685150124a7f87b3 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Mon, 1 Aug 2022 13:01:39 -0700 Subject: [PATCH 14/18] Update src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs Co-authored-by: Jan Kotas --- src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 23f452f352bb9..66e93c9d71d88 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -235,7 +235,7 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } default: - throw new NotImplementedException("Not Implemented"); + throw new InvalidOperationException(SR.InvalidOperation_UnknownEnumType); } } From abbcaa89426278e95de42b746712d59a7b360777 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Mon, 1 Aug 2022 15:54:02 -0700 Subject: [PATCH 15/18] Comment FB --- .../System.Private.CoreLib/src/System/Enum.cs | 25 +++++++++++-------- .../src/System/RuntimeType.cs | 8 +++--- .../System.Private.CoreLib/src/System/Type.cs | 10 ++++---- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index 623efb266de6f..89404415b5e17 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -323,28 +323,31 @@ public static Array GetValues(Type enumType) } /// - /// Gets an array of values of the underlying type of the Enum. + /// Retrieves an array of the values of the underlying type constants in a specified enumeration type. /// - /// Enum type + /// An enumeration type. /// /// - /// This method can be used to get enum values when creating an Array of Enum is challenging - /// For example, reflection-only context or on a platform where runtime codegen is not available. + /// This method can be used to get enumeration values when creating an array of the enumeration type is challenging. + /// For example, or on a platform where runtime codegen is not available. /// - /// Array of values containing the underlying type of the Enum + /// An array that contains the values of the underlying type constants in enumType. public static Array GetValuesAsUnderlyingType() where TEnum : struct, Enum => typeof(TEnum).GetEnumValuesAsUnderlyingType(); /// - /// Gets an array of values of the underlying type of the Enum. + /// Retrieves an array of the values of the underlying type constants in a specified enumeration. /// - /// Enum type + /// An enumeration type. /// - /// This method can be used to get enum values when creating an Array of Enum is challenging - /// For example, in reflection-only context or on a platform where runtime codegen is not available. + /// This method can be used to get enumeration values when creating an array of the enumeration type is challenging. + /// For example, or on a platform where runtime codegen is not available. /// - /// Array of values containing the underlying type of the Enum + /// An array that contains the values of the underlying type constants in . /// - /// Thrown when the enum type is null + /// Thrown when the enumeration type is null. + /// + /// + /// Thrown when the type is not an enumeration type. /// public static Array GetValuesAsUnderlyingType(Type enumType) { diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 66e93c9d71d88..ec5c617f8252e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -140,13 +140,13 @@ public override Array GetEnumValues() } /// - /// Gets an array of values of the underlying type of the Enum. + /// Retrieves an array of the values of the underlying type constants in a specified enumeration type. /// /// - /// This method can be used to get enum values when creating an Array of Enum is challenging - /// For example, in reflection-only context or on a platform where runtime codegen is not available. + /// This method can be used to get enumeration values when creating an array of the enumeration type is challenging. + /// For example, or on a platform where runtime codegen is not available. /// - /// Array of values containing the underlying type of the Enum + /// An array that contains the values of the underlying type constants in enumType. /// /// Thrown when the type is not Enum /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index f7210aa072ca2..e7a64d26f6827 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -527,15 +527,15 @@ public virtual Array GetEnumValues() } /// - /// Gets an array of values of the underlying type of the Enum. + /// Retrieves an array of the values of the underlying type constants in a specified enumeration type. /// /// - /// This method can be used to get enum values when creating an Array of Enum is challenging - /// For example, in reflection-only context or on a platform where runtime codegen is not available. + /// This method can be used to get enumeration values when creating an array of the enumeration type is challenging. + /// For example, or on a platform where runtime codegen is not available. /// - /// Array of values containing the underlying type of the Enum + /// An array that contains the values of the underlying type constants in enumType. /// - /// Thrown when the type is not Enum + /// Thrown when the type is not an enumeration type. /// public virtual Array GetEnumValuesAsUnderlyingType() => throw new NotSupportedException(SR.NotSupported_SubclassOverride); From b71f4665827b60775716fb538e9815174ddfc42b Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Mon, 1 Aug 2022 19:38:28 -0700 Subject: [PATCH 16/18] workaround mono test failures --- .../src/System/RuntimeType.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index ec5c617f8252e..0f24d868b2447 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -158,9 +158,18 @@ public override Array GetEnumValuesAsUnderlyingType() // Get all of the values ulong[] values = Enum.InternalGetValues(this); +#if MONO + switch (GetTypeCode(Enum.GetUnderlyingType(this))) +#else switch (RuntimeTypeHandle.GetCorElementType(this)) +#endif { + +#if MONO + case TypeCode.Byte: +#else case CorElementType.ELEMENT_TYPE_U1: +#endif { var ret = new byte[values.Length]; for (int i = 0; i < values.Length; i++) @@ -170,7 +179,11 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } +#if MONO + case TypeCode.UInt16: +#else case CorElementType.ELEMENT_TYPE_U2: +#endif { var ret = new ushort[values.Length]; for (int i = 0; i < values.Length; i++) @@ -180,7 +193,11 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } +#if MONO + case TypeCode.UInt32: +#else case CorElementType.ELEMENT_TYPE_U4: +#endif { var ret = new uint[values.Length]; for (int i = 0; i < values.Length; i++) @@ -190,12 +207,20 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } +#if MONO + case TypeCode.UInt64: +#else case CorElementType.ELEMENT_TYPE_U8: +#endif { return (Array)values.Clone(); } +#if MONO + case TypeCode.SByte: +#else case CorElementType.ELEMENT_TYPE_I1: +#endif { var ret = new sbyte[values.Length]; for (int i = 0; i < values.Length; i++) @@ -205,7 +230,11 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } +#if MONO + case TypeCode.Int16: +#else case CorElementType.ELEMENT_TYPE_I2: +#endif { var ret = new short[values.Length]; for (int i = 0; i < values.Length; i++) @@ -215,7 +244,11 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } +#if MONO + case TypeCode.Int32: +#else case CorElementType.ELEMENT_TYPE_I4: +#endif { var ret = new int[values.Length]; for (int i = 0; i < values.Length; i++) @@ -225,7 +258,11 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } +#if MONO + case TypeCode.Int64: +#else case CorElementType.ELEMENT_TYPE_I8: +#endif { var ret = new long[values.Length]; for (int i = 0; i < values.Length; i++) From d512cbca61b2ad80dff86474af3db2c3199bc61c Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Tue, 2 Aug 2022 04:03:34 -0700 Subject: [PATCH 17/18] Update src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs Co-authored-by: Jan Kotas --- src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 0f24d868b2447..c0cfb41c122dd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -159,7 +159,7 @@ public override Array GetEnumValuesAsUnderlyingType() ulong[] values = Enum.InternalGetValues(this); #if MONO - switch (GetTypeCode(Enum.GetUnderlyingType(this))) + switch (RuntimeTypeHandle.GetCorElementType(Enum.InternalGetUnderlyingType(this))) #else switch (RuntimeTypeHandle.GetCorElementType(this)) #endif From bb27de59b09834130964cece3a8f43daa935ef0a Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Tue, 2 Aug 2022 04:14:33 -0700 Subject: [PATCH 18/18] remove ifdefd --- .../src/System/RuntimeType.cs | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index c0cfb41c122dd..81d6f994da54f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -158,18 +158,10 @@ public override Array GetEnumValuesAsUnderlyingType() // Get all of the values ulong[] values = Enum.InternalGetValues(this); -#if MONO switch (RuntimeTypeHandle.GetCorElementType(Enum.InternalGetUnderlyingType(this))) -#else - switch (RuntimeTypeHandle.GetCorElementType(this)) -#endif { -#if MONO - case TypeCode.Byte: -#else case CorElementType.ELEMENT_TYPE_U1: -#endif { var ret = new byte[values.Length]; for (int i = 0; i < values.Length; i++) @@ -179,11 +171,7 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } -#if MONO - case TypeCode.UInt16: -#else case CorElementType.ELEMENT_TYPE_U2: -#endif { var ret = new ushort[values.Length]; for (int i = 0; i < values.Length; i++) @@ -193,11 +181,7 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } -#if MONO - case TypeCode.UInt32: -#else case CorElementType.ELEMENT_TYPE_U4: -#endif { var ret = new uint[values.Length]; for (int i = 0; i < values.Length; i++) @@ -207,20 +191,12 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } -#if MONO - case TypeCode.UInt64: -#else case CorElementType.ELEMENT_TYPE_U8: -#endif { return (Array)values.Clone(); } -#if MONO - case TypeCode.SByte: -#else case CorElementType.ELEMENT_TYPE_I1: -#endif { var ret = new sbyte[values.Length]; for (int i = 0; i < values.Length; i++) @@ -230,11 +206,7 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } -#if MONO - case TypeCode.Int16: -#else case CorElementType.ELEMENT_TYPE_I2: -#endif { var ret = new short[values.Length]; for (int i = 0; i < values.Length; i++) @@ -244,11 +216,7 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } -#if MONO - case TypeCode.Int32: -#else case CorElementType.ELEMENT_TYPE_I4: -#endif { var ret = new int[values.Length]; for (int i = 0; i < values.Length; i++) @@ -258,11 +226,7 @@ public override Array GetEnumValuesAsUnderlyingType() return ret; } -#if MONO - case TypeCode.Int64: -#else case CorElementType.ELEMENT_TYPE_I8: -#endif { var ret = new long[values.Length]; for (int i = 0; i < values.Length; i++)