diff --git a/src/libraries/System.Linq/src/System/Linq/OrderBy.cs b/src/libraries/System.Linq/src/System/Linq/OrderBy.cs index 2857c69ca6b80f..b276539109973d 100644 --- a/src/libraries/System.Linq/src/System/Linq/OrderBy.cs +++ b/src/libraries/System.Linq/src/System/Linq/OrderBy.cs @@ -140,14 +140,27 @@ public static IOrderedEnumerable ThenByDescending(this I /// Gets whether the results of an unstable sort will be observably the same as a stable sort. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool TypeIsImplicitlyStable() => - typeof(T) == typeof(sbyte) || typeof(T) == typeof(byte) || - typeof(T) == typeof(int) || typeof(T) == typeof(uint) || - typeof(T) == typeof(short) || typeof(T) == typeof(ushort) || - typeof(T) == typeof(long) || typeof(T) == typeof(ulong) || - typeof(T) == typeof(Int128) || typeof(T) == typeof(UInt128) || - typeof(T) == typeof(nint) || typeof(T) == typeof(nuint) || - typeof(T) == typeof(bool) || typeof(T) == typeof(char); + internal static bool TypeIsImplicitlyStable() + { + Type t = typeof(T); + if (typeof(T).IsEnum) + { + t = typeof(T).GetEnumUnderlyingType(); + } + + // Check for integral primitive types that compare equally iff they have the same bit pattern. + // bool is included because, even though technically it can have 256 different values, anything + // other than 0/1 is only producible using unsafe code. It's tempting to include a type like string + // here, as it's so commonly used with ordering, but two different string objects can compare equally, + // and their reference identity can be observable in a stable vs unstable sort. + return + t == typeof(sbyte) || t == typeof(byte) || t == typeof(bool) || + t == typeof(short) || t == typeof(ushort) || t == typeof(char) || + t == typeof(int) || t == typeof(uint) || + t == typeof(long) || t == typeof(ulong) || + t == typeof(Int128) || t == typeof(UInt128) || + t == typeof(nint) || t == typeof(nuint); + } } public interface IOrderedEnumerable : IEnumerable