e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
1228 lines
46 KiB
C#
1228 lines
46 KiB
C#
// ==++==
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// ==--==
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Collections;
|
|
using System.Globalization;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.Versioning;
|
|
using System.Diagnostics.Contracts;
|
|
|
|
namespace System
|
|
{
|
|
[Serializable]
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible
|
|
{
|
|
#region Private Static Data Members
|
|
private static readonly char [] enumSeperatorCharArray = new char [] {','};
|
|
private const String enumSeperator = ", ";
|
|
#endregion
|
|
|
|
#region Private Static Methods
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
private static ValuesAndNames GetCachedValuesAndNames(RuntimeType enumType, bool getNames)
|
|
{
|
|
ValuesAndNames entry = enumType.GenericCache as ValuesAndNames;
|
|
|
|
if (entry == null || (getNames && entry.Names == null))
|
|
{
|
|
ulong[] values = null;
|
|
String[] names = null;
|
|
|
|
#if MONO
|
|
if (!GetEnumValuesAndNames (enumType, out values, out names))
|
|
Array.Sort (values, names, System.Collections.Generic.Comparer<ulong>.Default);
|
|
#else
|
|
GetEnumValuesAndNames(
|
|
enumType.GetTypeHandleInternal(),
|
|
JitHelpers.GetObjectHandleOnStack(ref values),
|
|
JitHelpers.GetObjectHandleOnStack(ref names),
|
|
getNames);
|
|
#endif
|
|
entry = new ValuesAndNames(values, names);
|
|
enumType.GenericCache = entry;
|
|
}
|
|
|
|
return entry;
|
|
}
|
|
|
|
private static String InternalFormattedHexString(Object value)
|
|
{
|
|
TypeCode typeCode = Convert.GetTypeCode(value);
|
|
|
|
switch (typeCode)
|
|
{
|
|
case TypeCode.SByte :
|
|
{
|
|
Byte result = (byte)(sbyte)value;
|
|
|
|
return result.ToString("X2", null);
|
|
}
|
|
|
|
case TypeCode.Byte :
|
|
{
|
|
Byte result = (byte)value;
|
|
|
|
return result.ToString("X2", null);
|
|
}
|
|
|
|
case TypeCode.Boolean:
|
|
{
|
|
// direct cast from bool to byte is not allowed
|
|
Byte result = Convert.ToByte((bool)value);
|
|
|
|
return result.ToString("X2", null);
|
|
}
|
|
|
|
case TypeCode.Int16:
|
|
{
|
|
UInt16 result = (UInt16)(Int16)value;
|
|
|
|
return result.ToString("X4", null);
|
|
}
|
|
|
|
case TypeCode.UInt16 :
|
|
{
|
|
UInt16 result = (UInt16)value;
|
|
|
|
return result.ToString("X4", null);
|
|
}
|
|
|
|
case TypeCode.Char:
|
|
{
|
|
UInt16 result = (UInt16)(Char)value;
|
|
|
|
return result.ToString("X4", null);
|
|
}
|
|
|
|
case TypeCode.UInt32:
|
|
{
|
|
UInt32 result = (UInt32)value;
|
|
|
|
return result.ToString("X8", null);
|
|
}
|
|
|
|
case TypeCode.Int32 :
|
|
{
|
|
UInt32 result = (UInt32)(int)value;
|
|
|
|
return result.ToString("X8", null);
|
|
}
|
|
|
|
case TypeCode.UInt64 :
|
|
{
|
|
UInt64 result = (UInt64)value;
|
|
|
|
return result.ToString("X16", null);
|
|
}
|
|
|
|
case TypeCode.Int64 :
|
|
{
|
|
UInt64 result = (UInt64)(Int64)value;
|
|
|
|
return result.ToString("X16", null);
|
|
}
|
|
|
|
// All unsigned types will be directly cast
|
|
default :
|
|
Contract.Assert(false, "Invalid Object type in Format");
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
|
|
}
|
|
}
|
|
|
|
private static String InternalFormat(RuntimeType eT, Object value)
|
|
{
|
|
Contract.Requires(eT != null);
|
|
Contract.Requires(value != null);
|
|
if (!eT.IsDefined(typeof(System.FlagsAttribute), false)) // Not marked with Flags attribute
|
|
{
|
|
// Try to see if its one of the enum values, then we return a String back else the value
|
|
String retval = GetName(eT, value);
|
|
if (retval == null)
|
|
return value.ToString();
|
|
else
|
|
return retval;
|
|
}
|
|
else // These are flags OR'ed together (We treat everything as unsigned types)
|
|
{
|
|
return InternalFlagsFormat(eT, value);
|
|
|
|
}
|
|
}
|
|
|
|
private static String InternalFlagsFormat(RuntimeType eT, Object value)
|
|
{
|
|
Contract.Requires(eT != null);
|
|
Contract.Requires(value != null);
|
|
ulong result = ToUInt64(value);
|
|
|
|
// These values are sorted by value. Don't change this
|
|
ValuesAndNames entry = GetCachedValuesAndNames(eT, true);
|
|
|
|
String[] names = entry.Names;
|
|
ulong[] values = entry.Values;
|
|
Contract.Assert(names.Length == values.Length);
|
|
|
|
int index = values.Length - 1;
|
|
StringBuilder retval = new StringBuilder();
|
|
bool firstTime = true;
|
|
ulong saveResult = result;
|
|
|
|
// We will not optimize this code further to keep it maintainable. There are some boundary checks that can be applied
|
|
// to minimize the comparsions required. This code works the same for the best/worst case. In general the number of
|
|
// items in an enum are sufficiently small and not worth the optimization.
|
|
while (index >= 0)
|
|
{
|
|
if ((index == 0) && (values[index] == 0))
|
|
break;
|
|
|
|
if ((result & values[index]) == values[index])
|
|
{
|
|
result -= values[index];
|
|
if (!firstTime)
|
|
retval.Insert(0, enumSeperator);
|
|
|
|
retval.Insert(0, names[index]);
|
|
firstTime = false;
|
|
}
|
|
|
|
index--;
|
|
}
|
|
|
|
// We were unable to represent this number as a bitwise or of valid flags
|
|
if (result != 0)
|
|
return value.ToString();
|
|
|
|
// For the case when we have zero
|
|
if (saveResult==0)
|
|
{
|
|
if (values.Length > 0 && values[0] == 0)
|
|
return names[0]; // Zero was one of the enum values.
|
|
else
|
|
return "0";
|
|
}
|
|
else
|
|
return retval.ToString(); // Return the string representation
|
|
}
|
|
|
|
internal static ulong ToUInt64(Object value)
|
|
{
|
|
// Helper function to silently convert the value to UInt64 from the other base types for enum without throwing an exception.
|
|
// This is need since the Convert functions do overflow checks.
|
|
TypeCode typeCode = Convert.GetTypeCode(value);
|
|
ulong result;
|
|
|
|
switch(typeCode)
|
|
{
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.Int64:
|
|
result = (UInt64)Convert.ToInt64(value, CultureInfo.InvariantCulture);
|
|
break;
|
|
|
|
case TypeCode.Byte:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Char:
|
|
result = Convert.ToUInt64(value, CultureInfo.InvariantCulture);
|
|
break;
|
|
|
|
default:
|
|
// All unsigned types will be directly cast
|
|
Contract.Assert(false, "Invalid Object type in ToUInt64");
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private static extern int InternalCompareTo(Object o1, Object o2);
|
|
|
|
[System.Security.SecuritySafeCritical]
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern RuntimeType InternalGetUnderlyingType(RuntimeType enumType);
|
|
|
|
#if MONO
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private static extern bool GetEnumValuesAndNames (RuntimeType enumType, out ulong[] values, out string[] names);
|
|
#else
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
|
[System.Security.SuppressUnmanagedCodeSecurity]
|
|
private static extern void GetEnumValuesAndNames(RuntimeTypeHandle enumType, ObjectHandleOnStack values, ObjectHandleOnStack names, bool getNames);
|
|
#endif
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private static extern Object InternalBoxEnum(RuntimeType enumType, long value);
|
|
#endregion
|
|
|
|
#region Public Static Methods
|
|
private enum ParseFailureKind
|
|
{
|
|
None = 0,
|
|
Argument = 1,
|
|
ArgumentNull = 2,
|
|
ArgumentWithParameter = 3,
|
|
UnhandledException = 4
|
|
}
|
|
|
|
// This will store the result of the parsing.
|
|
private struct EnumResult
|
|
{
|
|
internal object parsedEnum;
|
|
internal bool canThrow;
|
|
internal ParseFailureKind m_failure;
|
|
internal string m_failureMessageID;
|
|
internal string m_failureParameter;
|
|
internal object m_failureMessageFormatArgument;
|
|
internal Exception m_innerException;
|
|
|
|
internal void Init(bool canMethodThrow)
|
|
{
|
|
parsedEnum = 0;
|
|
canThrow = canMethodThrow;
|
|
}
|
|
internal void SetFailure(Exception unhandledException)
|
|
{
|
|
m_failure = ParseFailureKind.UnhandledException;
|
|
m_innerException = unhandledException;
|
|
}
|
|
internal void SetFailure(ParseFailureKind failure, string failureParameter)
|
|
{
|
|
m_failure = failure;
|
|
m_failureParameter = failureParameter;
|
|
if (canThrow)
|
|
throw GetEnumParseException();
|
|
}
|
|
internal void SetFailure(ParseFailureKind failure, string failureMessageID, object failureMessageFormatArgument)
|
|
{
|
|
m_failure = failure;
|
|
m_failureMessageID = failureMessageID;
|
|
m_failureMessageFormatArgument = failureMessageFormatArgument;
|
|
if (canThrow)
|
|
throw GetEnumParseException();
|
|
}
|
|
internal Exception GetEnumParseException()
|
|
{
|
|
switch (m_failure)
|
|
{
|
|
case ParseFailureKind.Argument:
|
|
return new ArgumentException(Environment.GetResourceString(m_failureMessageID));
|
|
|
|
case ParseFailureKind.ArgumentNull:
|
|
return new ArgumentNullException(m_failureParameter);
|
|
|
|
case ParseFailureKind.ArgumentWithParameter:
|
|
return new ArgumentException(Environment.GetResourceString(m_failureMessageID, m_failureMessageFormatArgument));
|
|
|
|
case ParseFailureKind.UnhandledException:
|
|
return m_innerException;
|
|
|
|
default:
|
|
Contract.Assert(false, "Unknown EnumParseFailure: " + m_failure);
|
|
return new ArgumentException(Environment.GetResourceString("Arg_EnumValueNotFound"));
|
|
}
|
|
}
|
|
}
|
|
|
|
public static bool TryParse<TEnum>(String value, out TEnum result) where TEnum : struct
|
|
{
|
|
return TryParse(value, false, out result);
|
|
}
|
|
|
|
public static bool TryParse<TEnum>(String value, bool ignoreCase, out TEnum result) where TEnum : struct
|
|
{
|
|
result = default(TEnum);
|
|
EnumResult parseResult = new EnumResult();
|
|
parseResult.Init(false);
|
|
bool retValue;
|
|
|
|
if (retValue = TryParseEnum(typeof(TEnum), value, ignoreCase, ref parseResult))
|
|
result = (TEnum)parseResult.parsedEnum;
|
|
return retValue;
|
|
}
|
|
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Object Parse(Type enumType, String value)
|
|
{
|
|
return Parse(enumType, value, false);
|
|
}
|
|
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Object Parse(Type enumType, String value, bool ignoreCase)
|
|
{
|
|
EnumResult parseResult = new EnumResult();
|
|
parseResult.Init(true);
|
|
if (TryParseEnum(enumType, value, ignoreCase, ref parseResult))
|
|
return parseResult.parsedEnum;
|
|
else
|
|
throw parseResult.GetEnumParseException();
|
|
}
|
|
|
|
private static bool TryParseEnum(Type enumType, String value, bool ignoreCase, ref EnumResult parseResult)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
Contract.EndContractBlock();
|
|
|
|
RuntimeType rtType = enumType as RuntimeType;
|
|
if (rtType == null)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
|
|
|
|
if (!enumType.IsEnum)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
|
|
|
|
if (value == null) {
|
|
parseResult.SetFailure(ParseFailureKind.ArgumentNull, "value");
|
|
return false;
|
|
}
|
|
|
|
value = value.Trim();
|
|
if (value.Length == 0) {
|
|
parseResult.SetFailure(ParseFailureKind.Argument, "Arg_MustContainEnumInfo", null);
|
|
return false;
|
|
}
|
|
|
|
// We have 2 code paths here. One if they are values else if they are Strings.
|
|
// values will have the first character as as number or a sign.
|
|
ulong result = 0;
|
|
|
|
if (Char.IsDigit(value[0]) || value[0] == '-' || value[0] == '+')
|
|
{
|
|
Type underlyingType = GetUnderlyingType(enumType);
|
|
Object temp;
|
|
|
|
try
|
|
{
|
|
temp = Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture);
|
|
parseResult.parsedEnum = ToObject(enumType, temp);
|
|
return true;
|
|
}
|
|
catch (FormatException)
|
|
{ // We need to Parse this as a String instead. There are cases
|
|
// when you tlbimp enums that can have values of the form "3D".
|
|
// Don't fix this code.
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (parseResult.canThrow)
|
|
throw;
|
|
else
|
|
{
|
|
parseResult.SetFailure(ex);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
String[] values = value.Split(enumSeperatorCharArray);
|
|
|
|
// Find the field.Lets assume that these are always static classes because the class is
|
|
// an enum.
|
|
ValuesAndNames entry = GetCachedValuesAndNames(rtType, true);
|
|
|
|
String[] enumNames = entry.Names;
|
|
ulong[] enumValues = entry.Values;
|
|
|
|
for (int i = 0; i < values.Length; i++)
|
|
{
|
|
values[i] = values[i].Trim(); // We need to remove whitespace characters
|
|
|
|
bool success = false;
|
|
|
|
for (int j = 0; j < enumNames.Length; j++)
|
|
{
|
|
if (ignoreCase)
|
|
{
|
|
if (String.Compare(enumNames[j], values[i], StringComparison.OrdinalIgnoreCase) != 0)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (!enumNames[j].Equals(values[i]))
|
|
continue;
|
|
}
|
|
|
|
ulong item = enumValues[j];
|
|
|
|
result |= item;
|
|
success = true;
|
|
break;
|
|
}
|
|
|
|
if (!success)
|
|
{
|
|
// Not found, throw an argument exception.
|
|
parseResult.SetFailure(ParseFailureKind.ArgumentWithParameter, "Arg_EnumValueNotFound", value);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
parseResult.parsedEnum = ToObject(enumType, result);
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (parseResult.canThrow)
|
|
throw;
|
|
else
|
|
{
|
|
parseResult.SetFailure(ex);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Type GetUnderlyingType(Type enumType)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
Contract.Ensures(Contract.Result<Type>() != null);
|
|
Contract.EndContractBlock();
|
|
|
|
return enumType.GetEnumUnderlyingType();
|
|
}
|
|
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Array GetValues(Type enumType)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
Contract.Ensures(Contract.Result<Array>() != null);
|
|
Contract.EndContractBlock();
|
|
|
|
return enumType.GetEnumValues();
|
|
}
|
|
|
|
internal static ulong[] InternalGetValues(RuntimeType enumType)
|
|
{
|
|
// Get all of the values
|
|
return GetCachedValuesAndNames(enumType, false).Values;
|
|
}
|
|
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static String GetName(Type enumType, Object value)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
Contract.EndContractBlock();
|
|
|
|
return enumType.GetEnumName(value);
|
|
}
|
|
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static String[] GetNames(Type enumType)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
Contract.Ensures(Contract.Result<String[]>() != null);
|
|
Contract.EndContractBlock();
|
|
|
|
return enumType.GetEnumNames();
|
|
}
|
|
|
|
internal static String[] InternalGetNames(RuntimeType enumType)
|
|
{
|
|
// Get all of the names
|
|
return GetCachedValuesAndNames(enumType, true).Names;
|
|
}
|
|
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Object ToObject(Type enumType, Object value)
|
|
{
|
|
if (value == null)
|
|
throw new ArgumentNullException("value");
|
|
Contract.EndContractBlock();
|
|
|
|
// Delegate rest of error checking to the other functions
|
|
TypeCode typeCode = Convert.GetTypeCode(value);
|
|
|
|
// NetCF doesn't support char and boolean conversion
|
|
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8 &&
|
|
((typeCode == TypeCode.Boolean) || (typeCode == TypeCode.Char)))
|
|
{
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
|
|
}
|
|
|
|
|
|
switch (typeCode)
|
|
{
|
|
case TypeCode.Int32 :
|
|
return ToObject(enumType, (int)value);
|
|
|
|
case TypeCode.SByte :
|
|
return ToObject(enumType, (sbyte)value);
|
|
|
|
case TypeCode.Int16 :
|
|
return ToObject(enumType, (short)value);
|
|
|
|
case TypeCode.Int64 :
|
|
return ToObject(enumType, (long)value);
|
|
|
|
case TypeCode.UInt32 :
|
|
return ToObject(enumType, (uint)value);
|
|
|
|
case TypeCode.Byte :
|
|
return ToObject(enumType, (byte)value);
|
|
|
|
case TypeCode.UInt16 :
|
|
return ToObject(enumType, (ushort)value);
|
|
|
|
case TypeCode.UInt64 :
|
|
return ToObject(enumType, (ulong)value);
|
|
|
|
case TypeCode.Char:
|
|
return ToObject(enumType, (char)value);
|
|
|
|
case TypeCode.Boolean:
|
|
return ToObject(enumType, (bool)value);
|
|
|
|
default:
|
|
// All unsigned types will be directly cast
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
|
|
}
|
|
}
|
|
|
|
[Pure]
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static bool IsDefined(Type enumType, Object value)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
Contract.EndContractBlock();
|
|
|
|
return enumType.IsEnumDefined(value);
|
|
}
|
|
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static String Format(Type enumType, Object value, String format)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
|
|
if (!enumType.IsEnum)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
|
|
|
|
if (value == null)
|
|
throw new ArgumentNullException("value");
|
|
|
|
if (format == null)
|
|
throw new ArgumentNullException("format");
|
|
Contract.EndContractBlock();
|
|
|
|
RuntimeType rtType = enumType as RuntimeType;
|
|
if (rtType == null)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
|
|
|
|
// Check if both of them are of the same type
|
|
Type valueType = value.GetType();
|
|
|
|
Type underlyingType = GetUnderlyingType(enumType);
|
|
|
|
// If the value is an Enum then we need to extract the underlying value from it
|
|
if (valueType.IsEnum) {
|
|
Type valueUnderlyingType = GetUnderlyingType(valueType);
|
|
|
|
if (!valueType.IsEquivalentTo(enumType))
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_EnumAndObjectMustBeSameType", valueType.ToString(), enumType.ToString()));
|
|
|
|
valueType = valueUnderlyingType;
|
|
value = ((Enum)value).GetValue();
|
|
}
|
|
// The value must be of the same type as the Underlying type of the Enum
|
|
else if (valueType != underlyingType) {
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_EnumFormatUnderlyingTypeAndObjectMustBeSameType", valueType.ToString(), underlyingType.ToString()));
|
|
}
|
|
|
|
if( format.Length != 1) {
|
|
// all acceptable format string are of length 1
|
|
throw new FormatException(Environment.GetResourceString("Format_InvalidEnumFormatSpecification"));
|
|
}
|
|
|
|
char formatCh = format[0];
|
|
|
|
if (formatCh == 'D' || formatCh == 'd') {
|
|
return value.ToString();
|
|
}
|
|
|
|
if (formatCh == 'X' || formatCh == 'x') {
|
|
// Retrieve the value from the field.
|
|
return InternalFormattedHexString(value);
|
|
}
|
|
|
|
if (formatCh == 'G' || formatCh == 'g') {
|
|
return InternalFormat(rtType, value);
|
|
}
|
|
|
|
if (formatCh == 'F' || formatCh == 'f') {
|
|
return InternalFlagsFormat(rtType, value);
|
|
}
|
|
|
|
throw new FormatException(Environment.GetResourceString("Format_InvalidEnumFormatSpecification"));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Definitions
|
|
private class ValuesAndNames
|
|
{
|
|
// Each entry contains a list of sorted pair of enum field names and values, sorted by values
|
|
public ValuesAndNames(ulong[] values, String[] names)
|
|
{
|
|
this.Values = values;
|
|
this.Names = names;
|
|
}
|
|
|
|
public ulong[] Values;
|
|
public String[] Names;
|
|
}
|
|
#endregion
|
|
|
|
#if MONO
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
extern object get_value ();
|
|
#endif
|
|
|
|
#region Private Methods
|
|
[System.Security.SecuritySafeCritical]
|
|
internal unsafe Object GetValue()
|
|
{
|
|
#if MONO
|
|
return get_value ();
|
|
#else
|
|
fixed (void* pValue = &JitHelpers.GetPinningHelper(this).m_data)
|
|
{
|
|
switch (InternalGetCorElementType())
|
|
{
|
|
case CorElementType.I1:
|
|
return *(sbyte*)pValue;
|
|
case CorElementType.U1:
|
|
return *(byte*)pValue;
|
|
case CorElementType.Boolean:
|
|
return *(bool*)pValue;
|
|
case CorElementType.I2:
|
|
return *(short*)pValue;
|
|
case CorElementType.U2:
|
|
return *(ushort*)pValue;
|
|
case CorElementType.Char:
|
|
return *(char*)pValue;
|
|
case CorElementType.I4:
|
|
return *(int*)pValue;
|
|
case CorElementType.U4:
|
|
return *(uint*)pValue;
|
|
case CorElementType.R4:
|
|
return *(float*)pValue;
|
|
case CorElementType.I8:
|
|
return *(long*)pValue;
|
|
case CorElementType.U8:
|
|
return *(ulong*)pValue;
|
|
case CorElementType.R8:
|
|
return *(double*)pValue;
|
|
case CorElementType.I:
|
|
return *(IntPtr*)pValue;
|
|
case CorElementType.U:
|
|
return *(UIntPtr*)pValue;
|
|
default:
|
|
Contract.Assert(false, "Invalid primitive type");
|
|
return null;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern bool InternalHasFlag(Enum flags);
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
#if MONO
|
|
private extern int get_hashcode ();
|
|
#else
|
|
private extern CorElementType InternalGetCorElementType();
|
|
#endif
|
|
#endregion
|
|
|
|
#region Object Overrides
|
|
#if MONO
|
|
public override bool Equals (object obj)
|
|
{
|
|
return DefaultEquals (this, obj);
|
|
}
|
|
#else
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
public extern override bool Equals(Object obj);
|
|
#endif
|
|
[System.Security.SecuritySafeCritical]
|
|
public override unsafe int GetHashCode()
|
|
{
|
|
#if MONO
|
|
return get_hashcode ();
|
|
#else
|
|
// Avoid boxing by inlining GetValue()
|
|
// return GetValue().GetHashCode();
|
|
|
|
fixed (void* pValue = &JitHelpers.GetPinningHelper(this).m_data)
|
|
{
|
|
switch (InternalGetCorElementType())
|
|
{
|
|
case CorElementType.I1:
|
|
return (*(sbyte*)pValue).GetHashCode();
|
|
case CorElementType.U1:
|
|
return (*(byte*)pValue).GetHashCode();
|
|
case CorElementType.Boolean:
|
|
return (*(bool*)pValue).GetHashCode();
|
|
case CorElementType.I2:
|
|
return (*(short*)pValue).GetHashCode();
|
|
case CorElementType.U2:
|
|
return (*(ushort*)pValue).GetHashCode();
|
|
case CorElementType.Char:
|
|
return (*(char*)pValue).GetHashCode();
|
|
case CorElementType.I4:
|
|
return (*(int*)pValue).GetHashCode();
|
|
case CorElementType.U4:
|
|
return (*(uint*)pValue).GetHashCode();
|
|
case CorElementType.R4:
|
|
return (*(float*)pValue).GetHashCode();
|
|
case CorElementType.I8:
|
|
return (*(long*)pValue).GetHashCode();
|
|
case CorElementType.U8:
|
|
return (*(ulong*)pValue).GetHashCode();
|
|
case CorElementType.R8:
|
|
return (*(double*)pValue).GetHashCode();
|
|
case CorElementType.I:
|
|
return (*(IntPtr*)pValue).GetHashCode();
|
|
case CorElementType.U:
|
|
return (*(UIntPtr*)pValue).GetHashCode();
|
|
default:
|
|
Contract.Assert(false, "Invalid primitive type");
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
public override String ToString()
|
|
{
|
|
// Returns the value in a human readable format. For PASCAL style enums who's value maps directly the name of the field is returned.
|
|
// For PASCAL style enums who's values do not map directly the decimal value of the field is returned.
|
|
// For BitFlags (indicated by the Flags custom attribute): If for each bit that is set in the value there is a corresponding constant
|
|
//(a pure power of 2), then the OR string (ie "Red | Yellow") is returned. Otherwise, if the value is zero or if you can't create a string that consists of
|
|
// pure powers of 2 OR-ed together, you return a hex value
|
|
return Enum.InternalFormat((RuntimeType)GetType(), GetValue());
|
|
}
|
|
#endregion
|
|
|
|
#region IFormattable
|
|
[Obsolete("The provider argument is not used. Please use ToString(String).")]
|
|
public String ToString(String format, IFormatProvider provider)
|
|
{
|
|
return ToString(format);
|
|
}
|
|
#endregion
|
|
|
|
#region IComparable
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
public int CompareTo(Object target)
|
|
{
|
|
const int retIncompatibleMethodTables = 2; // indicates that the method tables did not match
|
|
const int retInvalidEnumType = 3; // indicates that the enum was of an unknown/unsupported unerlying type
|
|
|
|
if (this == null)
|
|
throw new NullReferenceException();
|
|
Contract.EndContractBlock();
|
|
|
|
int ret = InternalCompareTo(this, target);
|
|
|
|
if (ret < retIncompatibleMethodTables)
|
|
{
|
|
// -1, 0 and 1 are the normal return codes
|
|
return ret;
|
|
}
|
|
else if (ret == retIncompatibleMethodTables)
|
|
{
|
|
Type thisType = this.GetType();
|
|
Type targetType = target.GetType();
|
|
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_EnumAndObjectMustBeSameType",
|
|
targetType.ToString(), thisType.ToString()));
|
|
}
|
|
else
|
|
{
|
|
// assert valid return code (3)
|
|
Contract.Assert(ret == retInvalidEnumType, "Enum.InternalCompareTo return code was invalid");
|
|
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
public String ToString(String format) {
|
|
if (format == null || format.Length == 0)
|
|
format = "G";
|
|
|
|
if (String.Compare(format, "G", StringComparison.OrdinalIgnoreCase) == 0)
|
|
return ToString();
|
|
|
|
if (String.Compare(format, "D", StringComparison.OrdinalIgnoreCase) == 0)
|
|
return GetValue().ToString();
|
|
|
|
if (String.Compare(format, "X", StringComparison.OrdinalIgnoreCase) == 0)
|
|
return InternalFormattedHexString(GetValue());
|
|
|
|
if (String.Compare(format, "F", StringComparison.OrdinalIgnoreCase) == 0)
|
|
return InternalFlagsFormat((RuntimeType)GetType(), GetValue());
|
|
|
|
throw new FormatException(Environment.GetResourceString("Format_InvalidEnumFormatSpecification"));
|
|
}
|
|
|
|
[Obsolete("The provider argument is not used. Please use ToString().")]
|
|
public String ToString(IFormatProvider provider)
|
|
{
|
|
return ToString();
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical]
|
|
public Boolean HasFlag(Enum flag) {
|
|
if (flag == null)
|
|
throw new ArgumentNullException("flag");
|
|
Contract.EndContractBlock();
|
|
|
|
if (!this.GetType().IsEquivalentTo(flag.GetType())) {
|
|
throw new ArgumentException(Environment.GetResourceString("Argument_EnumTypeDoesNotMatch", flag.GetType(), this.GetType()));
|
|
}
|
|
|
|
return InternalHasFlag(flag);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IConvertable
|
|
public TypeCode GetTypeCode()
|
|
{
|
|
Type enumType = this.GetType();
|
|
Type underlyingType = GetUnderlyingType(enumType);
|
|
|
|
if (underlyingType == typeof(Int32))
|
|
{
|
|
return TypeCode.Int32;
|
|
}
|
|
|
|
if (underlyingType == typeof(sbyte))
|
|
{
|
|
return TypeCode.SByte;
|
|
}
|
|
|
|
if (underlyingType == typeof(Int16))
|
|
{
|
|
return TypeCode.Int16;
|
|
}
|
|
|
|
if (underlyingType == typeof(Int64))
|
|
{
|
|
return TypeCode.Int64;
|
|
}
|
|
|
|
if (underlyingType == typeof(UInt32))
|
|
{
|
|
return TypeCode.UInt32;
|
|
}
|
|
|
|
if (underlyingType == typeof(byte))
|
|
{
|
|
return TypeCode.Byte;
|
|
}
|
|
|
|
if (underlyingType == typeof(UInt16))
|
|
{
|
|
return TypeCode.UInt16;
|
|
}
|
|
|
|
if (underlyingType == typeof(UInt64))
|
|
{
|
|
return TypeCode.UInt64;
|
|
}
|
|
|
|
if (underlyingType == typeof(Boolean))
|
|
{
|
|
return TypeCode.Boolean;
|
|
}
|
|
|
|
if (underlyingType == typeof(Char))
|
|
{
|
|
return TypeCode.Char;
|
|
}
|
|
|
|
Contract.Assert(false, "Unknown underlying type.");
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
|
|
}
|
|
|
|
/// <internalonly/>
|
|
bool IConvertible.ToBoolean(IFormatProvider provider)
|
|
{
|
|
return Convert.ToBoolean(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
char IConvertible.ToChar(IFormatProvider provider)
|
|
{
|
|
return Convert.ToChar(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
sbyte IConvertible.ToSByte(IFormatProvider provider)
|
|
{
|
|
return Convert.ToSByte(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
byte IConvertible.ToByte(IFormatProvider provider)
|
|
{
|
|
return Convert.ToByte(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
short IConvertible.ToInt16(IFormatProvider provider)
|
|
{
|
|
return Convert.ToInt16(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
ushort IConvertible.ToUInt16(IFormatProvider provider)
|
|
{
|
|
return Convert.ToUInt16(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
int IConvertible.ToInt32(IFormatProvider provider)
|
|
{
|
|
return Convert.ToInt32(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
uint IConvertible.ToUInt32(IFormatProvider provider)
|
|
{
|
|
return Convert.ToUInt32(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
long IConvertible.ToInt64(IFormatProvider provider)
|
|
{
|
|
return Convert.ToInt64(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
ulong IConvertible.ToUInt64(IFormatProvider provider)
|
|
{
|
|
return Convert.ToUInt64(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
float IConvertible.ToSingle(IFormatProvider provider)
|
|
{
|
|
return Convert.ToSingle(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
double IConvertible.ToDouble(IFormatProvider provider)
|
|
{
|
|
return Convert.ToDouble(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
Decimal IConvertible.ToDecimal(IFormatProvider provider)
|
|
{
|
|
return Convert.ToDecimal(GetValue(), CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <internalonly/>
|
|
DateTime IConvertible.ToDateTime(IFormatProvider provider)
|
|
{
|
|
throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "Enum", "DateTime"));
|
|
}
|
|
|
|
/// <internalonly/>
|
|
Object IConvertible.ToType(Type type, IFormatProvider provider)
|
|
{
|
|
return Convert.DefaultToType((IConvertible)this, type, provider);
|
|
}
|
|
#endregion
|
|
|
|
#region ToObject
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[CLSCompliant(false)]
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Object ToObject(Type enumType, sbyte value)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
if (!enumType.IsEnum)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
|
|
Contract.EndContractBlock();
|
|
RuntimeType rtType = enumType as RuntimeType;
|
|
if (rtType == null)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
|
|
return InternalBoxEnum(rtType, value);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Object ToObject(Type enumType, short value)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
if (!enumType.IsEnum)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
|
|
Contract.EndContractBlock();
|
|
RuntimeType rtType = enumType as RuntimeType;
|
|
if (rtType == null)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
|
|
return InternalBoxEnum(rtType, value);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Object ToObject(Type enumType, int value)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
if (!enumType.IsEnum)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
|
|
Contract.EndContractBlock();
|
|
RuntimeType rtType = enumType as RuntimeType;
|
|
if (rtType == null)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
|
|
return InternalBoxEnum(rtType, value);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Object ToObject(Type enumType, byte value)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
if (!enumType.IsEnum)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
|
|
Contract.EndContractBlock();
|
|
RuntimeType rtType = enumType as RuntimeType;
|
|
if (rtType == null)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
|
|
return InternalBoxEnum(rtType, value);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[CLSCompliant(false)]
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Object ToObject(Type enumType, ushort value)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
if (!enumType.IsEnum)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
|
|
Contract.EndContractBlock();
|
|
RuntimeType rtType = enumType as RuntimeType;
|
|
if (rtType == null)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
|
|
return InternalBoxEnum(rtType, value);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[CLSCompliant(false)]
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Object ToObject(Type enumType, uint value)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
if (!enumType.IsEnum)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
|
|
Contract.EndContractBlock();
|
|
RuntimeType rtType = enumType as RuntimeType;
|
|
if (rtType == null)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
|
|
return InternalBoxEnum(rtType, value);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Object ToObject(Type enumType, long value)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
if (!enumType.IsEnum)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
|
|
Contract.EndContractBlock();
|
|
RuntimeType rtType = enumType as RuntimeType;
|
|
if (rtType == null)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
|
|
return InternalBoxEnum(rtType, value);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[CLSCompliant(false)]
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public static Object ToObject(Type enumType, ulong value)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
if (!enumType.IsEnum)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
|
|
Contract.EndContractBlock();
|
|
RuntimeType rtType = enumType as RuntimeType;
|
|
if (rtType == null)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
|
|
return InternalBoxEnum(rtType, unchecked((long)value));
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
private static Object ToObject(Type enumType, char value)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
if (!enumType.IsEnum)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
|
|
Contract.EndContractBlock();
|
|
RuntimeType rtType = enumType as RuntimeType;
|
|
if (rtType == null)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
|
|
return InternalBoxEnum(rtType, value);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
private static Object ToObject(Type enumType, bool value)
|
|
{
|
|
if (enumType == null)
|
|
throw new ArgumentNullException("enumType");
|
|
if (!enumType.IsEnum)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
|
|
Contract.EndContractBlock();
|
|
RuntimeType rtType = enumType as RuntimeType;
|
|
if (rtType == null)
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
|
|
return InternalBoxEnum(rtType, value ? 1 : 0);
|
|
}
|
|
#endregion
|
|
}
|
|
}
|