148 lines
4.3 KiB
C#
Raw Normal View History

using System.Reflection;
using System.Runtime.CompilerServices;
namespace System
{
partial class Enum
{
sealed class EnumInfo
{
public readonly bool HasFlagsAttribute;
public readonly ulong[] Values;
public readonly string[] Names;
// Each entry contains a list of sorted pair of enum field names and values, sorted by values
public EnumInfo (bool hasFlagsAttribute, ulong[] values, string[] names)
{
HasFlagsAttribute = hasFlagsAttribute;
Values = values;
Names = names;
}
}
public int CompareTo (object? target)
{
const int retIncompatibleMethodTables = 2; // indicates that the method tables did not match
int ret = InternalCompareTo (this, target);
if (ret < retIncompatibleMethodTables)
// -1, 0 and 1 are the normal return codes
return ret;
if (ret == retIncompatibleMethodTables)
throw new ArgumentException (SR.Format (SR.Arg_EnumAndObjectMustBeSameType, target!.GetType (), GetType ()));
throw new InvalidOperationException (SR.InvalidOperation_UnknownEnumType);
}
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern bool InternalHasFlag (Enum flags);
[Intrinsic]
public bool HasFlag (Enum flag)
{
if (flag is null)
throw new ArgumentNullException (nameof (flag));
if (!this.GetType ().IsEquivalentTo (flag.GetType ()))
throw new ArgumentException (SR.Format (SR.Argument_EnumTypeDoesNotMatch, flag.GetType (), this.GetType ()));
return InternalHasFlag (flag);
}
public static string? GetName (Type enumType, object value)
{
if (enumType is null)
throw new ArgumentNullException (nameof(enumType));
return enumType.GetEnumName (value);
}
public static string[] GetNames (Type enumType)
{
if (enumType is null)
throw new ArgumentNullException (nameof (enumType));
return enumType.GetEnumNames ();
}
public static Type GetUnderlyingType (Type enumType)
{
if (enumType is null)
throw new ArgumentNullException (nameof (enumType));
return enumType.GetEnumUnderlyingType ();
}
public static Array GetValues (Type enumType)
{
if (enumType is null)
throw new ArgumentNullException (nameof (enumType));
return enumType.GetEnumValues ();
}
public static bool IsDefined (Type enumType, object value)
{
if (enumType is null)
throw new ArgumentNullException (nameof (enumType));
return enumType.IsEnumDefined (value);
}
internal static ulong[] InternalGetValues (RuntimeType enumType)
{
// Get all of the values
return GetEnumInfo (enumType, false).Values;
}
internal static string[] InternalGetNames (RuntimeType enumType)
{
// Get all of the names
return GetEnumInfo (enumType, true).Names;
}
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern bool GetEnumValuesAndNames (RuntimeType enumType, out ulong[] values, out string[] names);
static EnumInfo GetEnumInfo (RuntimeType enumType, bool getNames = true)
{
var entry = enumType.GenericCache as EnumInfo;
if (entry == null || (getNames && entry.Names == null)) {
if (!GetEnumValuesAndNames (enumType, out var values, out var names))
Array.Sort (values, names, System.Collections.Generic.Comparer<ulong>.Default);
bool hasFlagsAttribute = enumType.IsDefined (typeof(FlagsAttribute), inherit: false);
entry = new EnumInfo (hasFlagsAttribute, values, names);
enumType.GenericCache = entry;
}
return entry;
}
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern object InternalBoxEnum (RuntimeType enumType, long value);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern int InternalCompareTo (object o1, object? o2);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern CorElementType InternalGetCorElementType ();
[MethodImplAttribute (MethodImplOptions.InternalCall)]
internal static extern RuntimeType InternalGetUnderlyingType (RuntimeType enumType);
static RuntimeType ValidateRuntimeType (Type enumType)
{
if (enumType is null)
throw new ArgumentNullException (nameof (enumType));
if (!enumType.IsEnum)
throw new ArgumentException (SR.Arg_MustBeEnum, nameof (enumType));
if (!(enumType is RuntimeType rtType))
throw new ArgumentException (SR.Arg_MustBeType, nameof (enumType));
return rtType;
}
}
}