2016-08-03 10:59:49 +00:00
// ==++==
//
// 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 ;
}
2019-04-12 14:10:50 +00:00
#if ! MONO
2016-08-03 10:59:49 +00:00
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
2019-04-12 14:10:50 +00:00
#endif
2016-08-03 10:59:49 +00:00
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern int InternalCompareTo ( Object o1 , Object o2 ) ;
2019-04-12 14:10:50 +00:00
#if ! MONO
2016-08-03 10:59:49 +00:00
[System.Security.SecuritySafeCritical]
[ResourceExposure(ResourceScope.None)]
2019-04-12 14:10:50 +00:00
#endif
2016-08-03 10:59:49 +00:00
[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
2019-04-12 14:10:50 +00:00
#if ! MONO
2016-08-03 10:59:49 +00:00
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
2019-04-12 14:10:50 +00:00
#endif
2016-08-03 10:59:49 +00:00
[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 ) ;
2019-04-12 14:10:50 +00:00
#if ! MONO
2016-08-03 10:59:49 +00:00
// 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" ) ;
}
2019-04-12 14:10:50 +00:00
#endif
2016-08-03 10:59:49 +00:00
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
}
2019-04-12 14:10:50 +00:00
#if ! MONO
2016-08-03 10:59:49 +00:00
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
2019-04-12 14:10:50 +00:00
#endif
2016-08-03 10:59:49 +00:00
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern bool InternalHasFlag ( Enum flags ) ;
[MethodImplAttribute(MethodImplOptions.InternalCall)]
#if MONO
private extern int get_hashcode ( ) ;
#else
2019-04-12 14:10:50 +00:00
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
2016-08-03 10:59:49 +00:00
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
2019-04-12 14:10:50 +00:00
#if MONO
public static TEnum Parse < TEnum > ( string value ) where TEnum : struct
{
return Parse < TEnum > ( value , false ) ;
}
public static TEnum Parse < TEnum > ( string value , bool ignoreCase ) where TEnum : struct
{
EnumResult parseResult = new EnumResult ( ) { canThrow = true } ;
if ( TryParseEnum ( typeof ( TEnum ) , value , ignoreCase , ref parseResult ) )
return ( TEnum ) parseResult . parsedEnum ;
else
throw parseResult . GetEnumParseException ( ) ;
}
public static bool TryParse ( Type enumType , String value , bool ignoreCase , out object result )
{
result = null ;
EnumResult parseResult = new EnumResult ( ) ;
bool retValue ;
if ( retValue = TryParseEnum ( enumType , value , ignoreCase , ref parseResult ) )
result = parseResult . parsedEnum ;
return retValue ;
}
public static bool TryParse ( Type enumType , String value , out object result )
{
return TryParse ( enumType , value , false , out result ) ;
}
#endif
2016-08-03 10:59:49 +00:00
}
}