+++ /dev/null
-//
-// System.Enum.cs
-//
-// Authors:
-// Miguel de Icaza (miguel@ximian.com)
-// Nick Drochak (ndrochak@gol.com)
-// Gonzalo Paniagua Javier (gonzalo@ximian.com)
-// Marek Safar (marek.safar@gmail.com)
-//
-// (C) Ximian, Inc. http://www.ximian.com
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
-// Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System.Collections;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Reflection;
-
-namespace System
-{
- internal struct MonoEnumInfo
- {
- internal Type utype;
- internal Array values;
- internal string[] names;
- internal Dictionary<string, int> name_hash;
- [ThreadStatic]
- static Dictionary<Type, MonoEnumInfo> cache;
- static readonly Dictionary<Type, MonoEnumInfo> global_cache = new Dictionary<Type, MonoEnumInfo> ();
- static object global_cache_monitor = new object ();
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- private static extern void get_enum_info (Type enumType, out MonoEnumInfo info);
-
- //
- // These comparers are needed because enumerations must be compared
- // using unsigned values so that negative numbers can be looked up
- // See bug: #371559
- //
- internal static SByteComparer sbyte_comparer = new SByteComparer ();
- internal static ShortComparer short_comparer = new ShortComparer ();
- internal static IntComparer int_comparer = new IntComparer ();
- internal static LongComparer long_comparer = new LongComparer ();
-
- internal class SByteComparer : IComparer, System.Collections.Generic.IComparer<sbyte>
- {
- public int Compare (object x, object y)
- {
- sbyte ix = (sbyte) x;
- sbyte iy = (sbyte) y;
-
- return ((byte) ix) - ((byte) iy);
- }
-
- public int Compare (sbyte ix, sbyte iy)
- {
- return ((byte) ix) - ((byte) iy);
- }
- }
-
- internal class ShortComparer : IComparer, System.Collections.Generic.IComparer<short>
- {
- public int Compare (object x, object y)
- {
- short ix = (short) x;
- short iy = (short) y;
-
- return ((ushort) ix) - ((ushort) iy);
- }
-
- public int Compare (short ix, short iy)
- {
- return ((ushort) ix) - ((ushort) iy);
- }
- }
-
- internal class IntComparer : IComparer, System.Collections.Generic.IComparer<int>
- {
- public int Compare (object x, object y)
- {
- int ix = (int) x;
- int iy = (int) y;
-
- if (ix == iy)
- return 0;
-
- if (((uint) ix) < ((uint) iy))
- return -1;
- return 1;
- }
-
- public int Compare (int ix, int iy)
- {
- if (ix == iy)
- return 0;
-
- if (((uint) ix) < ((uint) iy))
- return -1;
- return 1;
- }
- }
-
- internal class LongComparer : IComparer, System.Collections.Generic.IComparer<long>
- {
- public int Compare (object x, object y)
- {
- long ix = (long) x;
- long iy = (long) y;
-
- if (ix == iy)
- return 0;
- if (((ulong) ix) < ((ulong) iy))
- return -1;
- return 1;
- }
-
- public int Compare (long ix, long iy)
- {
- if (ix == iy)
- return 0;
- if (((ulong) ix) < ((ulong) iy))
- return -1;
- return 1;
- }
- }
-
- private MonoEnumInfo (MonoEnumInfo other)
- {
- utype = other.utype;
- values = other.values;
- names = other.names;
- name_hash = other.name_hash;
- }
-
- internal static void GetInfo (Type enumType, out MonoEnumInfo info)
- {
- var user_type = !(enumType is MonoType);
-
- if (user_type) {
- GetUserEnumInfo (enumType, out info);
- } else {
- /* First check the thread-local cache without locking */
- if (cache != null && cache.TryGetValue (enumType, out info)) {
- return;
- }
-
- /* Threads could die, so keep a global cache too */
- lock (global_cache_monitor) {
- if (global_cache.TryGetValue (enumType, out info)) {
- if (cache == null)
- cache = new Dictionary<Type, MonoEnumInfo> ();
-
- cache [enumType] = info;
- return;
- }
- }
-
- // TODO: return info with ulong values only to avoid all sorts of
- // Array trick and slow paths
- get_enum_info (enumType, out info);
- }
-
- SortEnums (info.utype, info.values, info.names);
-
- // User types can have unreliable/not-implemented GetHashCode
- if (user_type)
- return;
-
- if (info.names.Length > 50) {
- info.name_hash = new Dictionary<string, int> (info.names.Length);
- for (int i = 0; i < info.names.Length; ++i)
- info.name_hash [info.names [i]] = i;
- }
- MonoEnumInfo cached = new MonoEnumInfo (info);
- lock (global_cache_monitor) {
- global_cache [enumType] = cached;
- }
- }
-
- static void GetUserEnumInfo (Type type, out MonoEnumInfo mei)
- {
- mei = new MonoEnumInfo ();
- mei.utype = typeof (UInt64);
-
- var fields = type.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
- mei.names = new string [fields.Length];
- var values = new UInt64 [fields.Length];
- mei.values = values;
-
- for (int i = 0; i < fields.Length; ++i) {
- mei.names [i] = fields [i].Name;
- values [i] = ToUInt64 (fields [i].GetRawConstantValue ());
- }
- }
-
- public static ulong ToUInt64 (object value)
- {
- switch (Convert.GetTypeCode (value)) {
- case TypeCode.SByte:
- case TypeCode.Int16:
- case TypeCode.Int32:
- case TypeCode.Int64:
- return (UInt64) Convert.ToInt64 (value, CultureInfo.InvariantCulture);
-
- case TypeCode.Byte:
- case TypeCode.UInt16:
- case TypeCode.UInt32:
- case TypeCode.UInt64:
- case TypeCode.Boolean:
- case TypeCode.Char:
- return Convert.ToUInt64 (value, CultureInfo.InvariantCulture);
-
- default:
- throw new ArgumentException ("Value is not the enum or a valid enum underlying type", "value");
- }
- }
-
- internal static void SortEnums (Type et, Array values, string[] names)
- {
- IComparer ic;
- if (et == typeof (int))
- ic = int_comparer;
- else if (et == typeof (short))
- ic = short_comparer;
- else if (et == typeof (sbyte))
- ic = sbyte_comparer;
- else if (et == typeof (long))
- ic = long_comparer;
- else
- ic = null;
-
- Array.Sort (values, names, ic);
- }
- }
-
- [Serializable]
- [ComVisible (true)]
- public abstract class Enum : ValueType, IComparable, IConvertible, IFormattable
- {
- protected Enum ()
- {
- }
-
- // IConvertible methods Start -->
- public TypeCode GetTypeCode ()
- {
- return Type.GetTypeCode (GetUnderlyingType (this.GetType ()));
- }
-
- bool IConvertible.ToBoolean (IFormatProvider provider)
- {
- return Convert.ToBoolean (Value, provider);
- }
-
- byte IConvertible.ToByte (IFormatProvider provider)
- {
- return Convert.ToByte (Value, provider);
- }
-
- char IConvertible.ToChar (IFormatProvider provider)
- {
- return Convert.ToChar (Value, provider);
- }
-
- DateTime IConvertible.ToDateTime (IFormatProvider provider)
- {
- return Convert.ToDateTime (Value, provider);
- }
-
- decimal IConvertible.ToDecimal (IFormatProvider provider)
- {
- return Convert.ToDecimal (Value, provider);
- }
-
- double IConvertible.ToDouble (IFormatProvider provider)
- {
- return Convert.ToDouble (Value, provider);
- }
-
- short IConvertible.ToInt16 (IFormatProvider provider)
- {
- return Convert.ToInt16 (Value, provider);
- }
-
- int IConvertible.ToInt32 (IFormatProvider provider)
- {
- return Convert.ToInt32 (Value, provider);
- }
-
- long IConvertible.ToInt64 (IFormatProvider provider)
- {
- return Convert.ToInt64 (Value, provider);
- }
-
- sbyte IConvertible.ToSByte (IFormatProvider provider)
- {
- return Convert.ToSByte (Value, provider);
- }
-
- float IConvertible.ToSingle (IFormatProvider provider)
- {
- return Convert.ToSingle (Value, provider);
- }
-
- object IConvertible.ToType (Type type, IFormatProvider provider)
- {
- return Convert.DefaultToType ((IConvertible)this, type, provider);
- }
-
- ushort IConvertible.ToUInt16 (IFormatProvider provider)
- {
- return Convert.ToUInt16 (Value, provider);
- }
-
- uint IConvertible.ToUInt32 (IFormatProvider provider)
- {
- return Convert.ToUInt32 (Value, provider);
- }
-
- ulong IConvertible.ToUInt64 (IFormatProvider provider)
- {
- return Convert.ToUInt64 (Value, provider);
- }
-
- // <-- End IConvertible methods
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- private extern object get_value ();
-
- // wrap the icall into a property so we don't hav to use the icall everywhere
- private object Value {
- get { return get_value (); }
- }
-
- [ComVisible (true)]
- public static Array GetValues (Type enumType)
- {
- if (enumType == null)
- throw new ArgumentNullException ("enumType");
-
- if (!enumType.IsEnum)
- throw new ArgumentException ("enumType is not an Enum type.", "enumType");
-
- MonoEnumInfo info;
- MonoEnumInfo.GetInfo (enumType, out info);
- return (Array) info.values.Clone ();
- }
-
- [ComVisible (true)]
- public static string[] GetNames (Type enumType)
- {
- if (enumType == null)
- throw new ArgumentNullException ("enumType");
-
- if (!enumType.IsEnum)
- throw new ArgumentException ("enumType is not an Enum type.");
-
- MonoEnumInfo info;
- MonoEnumInfo.GetInfo (enumType, out info);
- return (string []) info.names.Clone ();
- }
-
- //
- // The faster, non-boxing version. It must use the special MonoEnumInfo.xxx_comparers
- // to ensure that we are perfoming bitwise compares, and not signed compares.
- //
- // It also tries to use the non-boxing version of the various Array.BinarySearch methods
- //
- static int FindPosition (Type underlyingEnumType, object value, Array values)
- {
- switch (Type.GetTypeCode (underlyingEnumType)) {
- case TypeCode.SByte:
- sbyte [] sbyte_array = values as sbyte [];
- return Array.BinarySearch (sbyte_array, (sbyte) value, MonoEnumInfo.sbyte_comparer);
-
- case TypeCode.Byte:
- byte [] byte_array = values as byte [];
- return Array.BinarySearch (byte_array, (byte) value);
-
- case TypeCode.Int16:
- short [] short_array = values as short [];
- return Array.BinarySearch (short_array, (short)value, MonoEnumInfo.short_comparer);
-
- case TypeCode.UInt16:
- ushort [] ushort_array = values as ushort [];
- return Array.BinarySearch (ushort_array, (ushort)value);
-
- case TypeCode.Int32:
- int[] int_array = values as int[];
- return Array.BinarySearch (int_array, (int)value, MonoEnumInfo.int_comparer);
-
- case TypeCode.UInt32:
- uint[] uint_array = values as uint [];
- return Array.BinarySearch (uint_array, (uint)value);
-
- case TypeCode.Int64:
- long [] long_array = values as long [];
- return Array.BinarySearch (long_array, (long) value, MonoEnumInfo.long_comparer);
-
- case TypeCode.UInt64:
- ulong [] ulong_array = values as ulong [];
- return Array.BinarySearch (ulong_array, (ulong) value);
-
- default:
- // This should never happen
- throw new NotSupportedException ("Unknown underlying enum type");
- }
- }
-
- [ComVisible (true)]
- public static string GetName (Type enumType, object value)
- {
- if (enumType == null)
- throw new ArgumentNullException ("enumType");
- if (value == null)
- throw new ArgumentNullException ("value");
-
- if (!enumType.IsEnum)
- throw new ArgumentException ("enumType is not an Enum type.", "enumType");
-
- MonoEnumInfo info;
- MonoEnumInfo.GetInfo (enumType, out info);
-
- if (enumType is MonoType)
- value = ToObject (enumType, value);
- else
- value = MonoEnumInfo.ToUInt64 (value);
-
- int i = FindPosition (info.utype, value, info.values);
- return (i >= 0) ? info.names [i] : null;
- }
-
- [ComVisible (true)]
- public static bool IsDefined (Type enumType, object value)
- {
- if (enumType == null)
- throw new ArgumentNullException ("enumType");
- if (value == null)
- throw new ArgumentNullException ("value");
-
- if (!enumType.IsEnum)
- throw new ArgumentException ("enumType is not an Enum type.", "enumType");
-
- MonoEnumInfo info;
- MonoEnumInfo.GetInfo (enumType, out info);
-
- Type vType = value.GetType ();
- if (vType == typeof (String)) {
- return ((IList)(info.names)).Contains (value);
- }
-
- if ((vType == info.utype || !(enumType is MonoType)) || (vType == enumType)) {
- if (enumType is MonoType)
- value = ToObject (enumType, value);
- else
- value = MonoEnumInfo.ToUInt64 (value);
-
- MonoEnumInfo.GetInfo (enumType, out info);
- return FindPosition (info.utype, value, info.values) >= 0;
- }
-
- if (IsValidEnumType (info.utype))
- throw new ArgumentException("The value parameter is not the correct type. "
- + "It must be type String or the same type as the underlying type "
- + "of the Enum.");
-
- throw new InvalidOperationException ("Unknown enum type.");
- }
-
- static bool IsValidEnumType (Type type)
- {
- return (type.IsPrimitive && type != typeof (double) && type != typeof (float));
- }
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- private static extern Type get_underlying_type (Type enumType);
-
- [ComVisible (true)]
- public static Type GetUnderlyingType (Type enumType)
- {
- if (enumType == null)
- throw new ArgumentNullException ("enumType");
-
- if (!enumType.IsEnum)
- throw new ArgumentException ("enumType is not an Enum type.", "enumType");
-
- return get_underlying_type (enumType);
- }
-
- [ComVisible (true)]
- public static object Parse (Type enumType, string value)
- {
- // Note: Parameters are checked in the other overload
- return Parse (enumType, value, false);
- }
-
- private static int FindName (IDictionary<string, int> name_hash, string [] names, string name, bool ignoreCase)
- {
- if (!ignoreCase) {
- /* For enums with many values, use a hash table */
- if (name_hash != null) {
- int val;
- if (name_hash.TryGetValue (name, out val))
- return val;
- } else {
- for (int i = 0; i < names.Length; ++i) {
- if (name == names [i])
- return i;
- }
- }
- } else {
- for (int i = 0; i < names.Length; ++i) {
- if (String.Compare (name, names [i], ignoreCase, CultureInfo.InvariantCulture) == 0)
- return i;
- }
- }
- return -1;
- }
-
- // Helper function for dealing with [Flags]-style enums.
- private static ulong GetValue (object value, TypeCode typeCode)
- {
- switch (typeCode) {
- case TypeCode.Byte:
- return (byte) value;
- case TypeCode.SByte:
- return (byte) ((sbyte) value);
- case TypeCode.Int16:
- return (ushort) ((short) value);
- case TypeCode.Int32:
- return (uint) ((int) value);
- case TypeCode.Int64:
- return (ulong) ((long) value);
- case TypeCode.UInt16:
- return (ushort) value;
- case TypeCode.UInt32:
- return (uint) value;
- case TypeCode.UInt64:
- return (ulong) value;
- }
- throw new ArgumentException ("typeCode is not a valid type code for an Enum");
- }
-
- [ComVisible(true)]
- public static object Parse (Type enumType, string value, bool ignoreCase)
- {
- if (enumType == null)
- throw new ArgumentNullException ("enumType");
-
- if (value == null)
- throw new ArgumentNullException ("value");
-
- if (!enumType.IsEnum)
- throw new ArgumentException ("enumType is not an Enum type.", "enumType");
-
- value = value.Trim ();
- if (value.Length == 0)
- throw new ArgumentException ("An empty string is not considered a valid value.");
-
- object result;
- if (!Parse (enumType, value, ignoreCase, out result))
- throw new ArgumentException (String.Format ("The requested value '{0}' was not found.", value));
-
- return result;
- }
-
- static char [] split_char;
-
- static bool Parse<TEnum> (Type enumType, string value, bool ignoreCase, out TEnum result)
- {
- result = default (TEnum);
-
- MonoEnumInfo info;
- MonoEnumInfo.GetInfo (enumType, out info);
-
- // is 'value' a named constant?
- int loc = FindName (info.name_hash, info.names, value, ignoreCase);
- if (loc >= 0) {
- result = (TEnum) info.values.GetValue (loc);
- return true;
- }
-
- TypeCode typeCode = ((Enum) info.values.GetValue (0)).GetTypeCode ();
-
- // is 'value' a list of named constants?
- if (value.IndexOf (',') != -1) {
- if (split_char == null)
- split_char = new [] { ',' };
- string [] names = value.Split (split_char);
- ulong retVal = 0;
- for (int i = 0; i < names.Length; ++i) {
- loc = FindName (info.name_hash, info.names, names [i].Trim (), ignoreCase);
- if (loc < 0)
- return false;
-
- retVal |= GetValue (info.values.GetValue (loc), typeCode);
- }
- result = (TEnum) ToObject (enumType, retVal);
- return true;
- }
-
- // is 'value' a number?
- switch (typeCode) {
- case TypeCode.SByte:
- sbyte sb;
- if (!SByte.TryParse (value, out sb))
- return false;
- result = (TEnum) ToObject (enumType, sb);
- break;
- case TypeCode.Byte:
- byte b;
- if (!Byte.TryParse (value, out b))
- return false;
- result = (TEnum) ToObject (enumType, b);
- break;
- case TypeCode.Int16:
- short i16;
- if (!Int16.TryParse (value, out i16))
- return false;
- result = (TEnum) ToObject (enumType, i16);
- break;
- case TypeCode.UInt16:
- ushort u16;
- if (!UInt16.TryParse (value, out u16))
- return false;
- result = (TEnum) ToObject (enumType, u16);
- break;
- case TypeCode.Int32:
- int i32;
- if (!Int32.TryParse (value, out i32))
- return false;
- result = (TEnum) ToObject (enumType, i32);
- break;
- case TypeCode.UInt32:
- uint u32;
- if (!UInt32.TryParse (value, out u32))
- return false;
- result = (TEnum) ToObject (enumType, u32);
- break;
- case TypeCode.Int64:
- long i64;
- if (!Int64.TryParse (value, out i64))
- return false;
- result = (TEnum) ToObject (enumType, i64);
- break;
- case TypeCode.UInt64:
- ulong u64;
- if (!UInt64.TryParse (value, out u64))
- return false;
- result = (TEnum) ToObject (enumType, u64);
- break;
- default:
- break;
- }
-
- return true;
- }
-
- 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
- {
- Type tenum_type = typeof (TEnum);
- if (!tenum_type.IsEnum)
- throw new ArgumentException("TEnum is not an Enum type.", "enumType");
-
- result = default (TEnum);
-
- if (value == null)
- return false;
-
- value = value.Trim ();
- if (value.Length == 0)
- return false;
-
- return Parse (tenum_type, value, ignoreCase, out result);
- }
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- private extern int compare_value_to (object other);
-
- /// <summary>
- /// Compares the enum value with another enum value of the same type.
- /// </summary>
- ///
- /// <remarks/>
- public int CompareTo (object target)
- {
- Type thisType;
-
- if (target == null)
- return 1;
-
- thisType = this.GetType ();
- if (target.GetType() != thisType) {
- throw new ArgumentException (String.Format (
- "Object must be the same type as the enum. The type passed in was {0}; the enum type was {1}.",
- target.GetType(), thisType));
- }
-
- return compare_value_to (target);
- }
-
- public override string ToString ()
- {
- return Format (GetType (), Value, "G");
- }
-
- [Obsolete("Provider is ignored, just use ToString")]
- public string ToString (IFormatProvider provider)
- {
- return ToString ("G", provider);
- }
-
- public string ToString (String format)
- {
- if (format == String.Empty || format == null)
- format = "G";
-
- return Format (this.GetType (), this.Value, format);
- }
-
- [Obsolete("Provider is ignored, just use ToString")]
- public string ToString (String format, IFormatProvider provider)
- {
- // provider is not used for Enums
-
- if (format == String.Empty || format == null) {
- format = "G";
- }
- return Format (this.GetType(), this.Value, format);
- }
-
- [ComVisible (true)]
- public static object ToObject (Type enumType, byte value)
- {
- return ToObject (enumType, (object)value);
- }
-
- [ComVisible (true)]
- public static object ToObject (Type enumType, short value)
- {
- return ToObject (enumType, (object)value);
- }
-
- [ComVisible (true)]
- public static object ToObject (Type enumType, int value)
- {
- return ToObject (enumType, (object)value);
- }
-
- [ComVisible (true)]
- public static object ToObject (Type enumType, long value)
- {
- return ToObject (enumType, (object)value);
- }
-
- [ComVisible (true)]
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- public static extern object ToObject (Type enumType, object value);
-
- [ComVisible (true)]
- [CLSCompliant (false)]
- public static object ToObject (Type enumType, sbyte value)
- {
- return ToObject (enumType, (object)value);
- }
-
- [ComVisible (true)]
- [CLSCompliant (false)]
- public static object ToObject (Type enumType, ushort value)
- {
- return ToObject (enumType, (object)value);
- }
-
- [ComVisible (true)]
- [CLSCompliant (false)]
- public static object ToObject (Type enumType, uint value)
- {
- return ToObject (enumType, (object)value);
- }
-
- [ComVisible (true)]
- [CLSCompliant (false)]
- public static object ToObject (Type enumType, ulong value)
- {
- return ToObject (enumType, (object)value);
- }
-
- public override bool Equals (object obj)
- {
- return DefaultEquals (this, obj);
- }
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- private extern int get_hashcode ();
-
- public override int GetHashCode ()
- {
- return get_hashcode ();
- }
-
- private static string FormatSpecifier_X (Type enumType, object value, bool upper)
- {
- switch (Type.GetTypeCode (enumType)) {
- case TypeCode.SByte:
- return NumberFormatter.NumberToString (upper ? "X2" : "x2", ((sbyte)value), null);
- case TypeCode.Byte:
- return NumberFormatter.NumberToString (upper ? "X2" : "x2", ((byte)value), null);
- case TypeCode.Int16:
- return NumberFormatter.NumberToString (upper ? "X4" : "x4", ((short)value), null);
- case TypeCode.UInt16:
- return NumberFormatter.NumberToString (upper ? "X4" : "x4", ((ushort)value), null);
- case TypeCode.Int32:
- return NumberFormatter.NumberToString (upper ? "X8" : "x8", ((int)value), null);
- case TypeCode.UInt32:
- return NumberFormatter.NumberToString (upper ? "X8" : "x8", ((uint)value), null);
- case TypeCode.Int64:
- return NumberFormatter.NumberToString (upper ? "X16" : "x16", ((long)value), null);
- case TypeCode.UInt64:
- return NumberFormatter.NumberToString (upper ? "X16" : "x16", ((ulong)value), null);
- default:
- throw new Exception ("Invalid type code for enumeration.");
- }
- }
-
- static string FormatFlags (Type enumType, object value)
- {
- string retVal = String.Empty;
- MonoEnumInfo info;
- MonoEnumInfo.GetInfo (enumType, out info);
- string asString = value.ToString ();
- if (asString == "0") {
- retVal = GetName (enumType, value);
- if (retVal == null)
- retVal = asString;
- return retVal;
- }
- // This is ugly, yes. We need to handle the different integer
- // types for enums. If someone else has a better idea, be my guest.
- switch (((Enum)info.values.GetValue (0)).GetTypeCode ()) {
- case TypeCode.SByte: {
- sbyte flags = (sbyte) value;
- sbyte enumValue;
- for (int i = info.values.Length - 1; i >= 0; i--) {
- enumValue = (sbyte) info.values.GetValue (i);
- if (enumValue == 0)
- continue;
-
- if ((flags & enumValue) == enumValue) {
- retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
- flags -= enumValue;
- }
- }
- if (flags != 0) return asString;
- }
- break;
- case TypeCode.Byte: {
- byte flags = (byte) value;
- byte enumValue;
- for (int i = info.values.Length - 1; i >= 0; i--) {
- enumValue = (byte) info.values.GetValue (i);
- if (enumValue == 0)
- continue;
-
- if ((flags & enumValue) == enumValue) {
- retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
- flags -= enumValue;
- }
- }
- if (flags != 0) return asString;
- }
- break;
- case TypeCode.Int16: {
- short flags = (short) value;
- short enumValue;
- for (int i = info.values.Length - 1; i >= 0; i--) {
- enumValue = (short) info.values.GetValue (i);
- if (enumValue == 0)
- continue;
-
- if ((flags & enumValue) == enumValue) {
- retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
- flags -= enumValue;
- }
- }
- if (flags != 0) return asString;
- }
- break;
- case TypeCode.Int32: {
- int flags = (int) value;
- int enumValue;
- for (int i = info.values.Length - 1; i >= 0; i--) {
- enumValue = (int) info.values.GetValue (i);
- if (enumValue == 0)
- continue;
-
- if ((flags & enumValue) == enumValue) {
- retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
- flags -= enumValue;
- }
- }
- if (flags != 0) return asString;
- }
- break;
- case TypeCode.UInt16: {
- ushort flags = (ushort) value;
- ushort enumValue;
- for (int i = info.values.Length - 1; i >= 0; i--) {
- enumValue = (ushort) info.values.GetValue (i);
- if (enumValue == 0)
- continue;
-
- if ((flags & enumValue) == enumValue) {
- retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
- flags -= enumValue;
- }
- }
- if (flags != 0) return asString;
- }
- break;
- case TypeCode.UInt32: {
- uint flags = (uint) value;
- uint enumValue;
- for (int i = info.values.Length - 1; i >= 0; i--) {
- enumValue = (uint) info.values.GetValue (i);
- if (enumValue == 0)
- continue;
-
- if ((flags & enumValue) == enumValue) {
- retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
- flags -= enumValue;
- }
- }
- if (flags != 0) return asString;
- }
- break;
- case TypeCode.Int64: {
- long flags = (long) value;
- long enumValue;
- for (int i = info.values.Length - 1; i >= 0; i--) {
- enumValue = (long) info.values.GetValue (i);
- if (enumValue == 0)
- continue;
-
- if ((flags & enumValue) == enumValue) {
- retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
- flags -= enumValue;
- }
- }
- if (flags != 0) return asString;
- }
- break;
- case TypeCode.UInt64: {
- ulong flags = (ulong) value;
- ulong enumValue;
- for (int i = info.values.Length - 1; i >= 0; i--) {
- enumValue = (ulong) info.values.GetValue (i);
- if (enumValue == 0)
- continue;
-
- if ((flags & enumValue) == enumValue) {
- retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
- flags -= enumValue;
- }
- }
- if (flags != 0) return asString;
- }
- break;
- }
-
- if (retVal == String.Empty)
- return asString;
-
- return retVal;
- }
-
- [ComVisible (true)]
- public static string Format (Type enumType, object value, string format)
- {
- if (enumType == null)
- throw new ArgumentNullException ("enumType");
- if (value == null)
- throw new ArgumentNullException ("value");
- if (format == null)
- throw new ArgumentNullException ("format");
-
- if (!enumType.IsEnum)
- throw new ArgumentException ("enumType is not an Enum type.", "enumType");
-
- Type vType = value.GetType();
- Type underlyingType = Enum.GetUnderlyingType (enumType);
- if (vType.IsEnum) {
- if (vType != enumType)
- throw new ArgumentException (string.Format(
- "Object must be the same type as the enum. The type" +
- " passed in was {0}; the enum type was {1}.",
- vType.FullName, enumType.FullName));
- } else if (vType != underlyingType) {
- throw new ArgumentException (string.Format (
- "Enum underlying type and the object must be the same type" +
- " or object. Type passed in was {0}; the enum underlying" +
- " type was {1}.", vType.FullName, underlyingType.FullName));
- }
-
- if (format.Length == 1) {
- switch (format [0]) {
- case 'f':
- case 'F':
- return FormatFlags (enumType, value);
- case 'g':
- case 'G':
- if (!enumType.IsDefined (typeof(FlagsAttribute), false))
- return GetName (enumType, value) ?? value.ToString ();
-
- goto case 'f';
- case 'X':
- return FormatSpecifier_X (enumType, value, true);
- case 'x':
- return FormatSpecifier_X (enumType, value, false);
- case 'D':
- case 'd':
- if (vType.IsEnum)
- value = ((Enum) value).Value;
-
- return value.ToString ();
- }
- }
-
- throw new FormatException ("Format String can be only \"G\",\"g\",\"X\"," +
- "\"x\",\"F\",\"f\",\"D\" or \"d\".");
- }
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- private static extern bool InternalHasFlag (Enum a, Enum b);
-
- public bool HasFlag (Enum flag)
- {
- if (flag == null)
- throw new ArgumentNullException ("flag");
-
- if (!this.GetType ().IsEquivalentTo (flag.GetType ()))
- throw new ArgumentException (Environment.GetResourceString ("Argument_EnumTypeDoesNotMatch", flag.GetType (), this.GetType ()));
-
- return InternalHasFlag (this, flag);
- }
- }
-}
return !Object.ReferenceEquals (left, right);
}
- [MonoInternalNote ("Reimplement this in MonoType for bonus speed")]
- public virtual Type GetEnumUnderlyingType () {
- if (!IsEnum)
- throw new ArgumentException ("Type is not an enumeration", "enumType");
-
- var fields = GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
-
- if (fields == null || fields.Length != 1)
- throw new ArgumentException ("An enum must have exactly one instance field", "enumType");
-
- return fields [0].FieldType;
- }
-
- [MonoInternalNote ("Reimplement this in MonoType for bonus speed")]
- public virtual string[] GetEnumNames () {
- if (!IsEnum)
- throw new ArgumentException ("Type is not an enumeration", "enumType");
-
- var fields = GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
-
- string [] names = new string [fields.Length];
- if (0 != names.Length) {
- for (int i = 0; i < fields.Length; ++i)
- names [i] = fields [i].Name;
-
- var et = GetEnumUnderlyingType ();
- var values = Array.CreateInstance (et, names.Length);
- for (int i = 0; i < fields.Length; ++i)
- values.SetValue (fields [i].GetValue (null), i);
- MonoEnumInfo.SortEnums (et, values, names);
- }
-
- return names;
- }
-
static NotImplementedException CreateNIE () {
return new NotImplementedException ();
}
- public virtual Array GetEnumValues () {
- if (!IsEnum)
- throw new ArgumentException ("Type is not an enumeration", "enumType");
-
- throw CreateNIE ();
- }
-
- public virtual string GetEnumName (object value)
- {
- return Enum.GetName (this, value);
- }
-
- public virtual bool IsEnumDefined (object value)
- {
- return Enum.IsDefined (this, value);
- }
-
public static Type GetType (string typeName, Func<AssemblyName,Assembly> assemblyResolver, Func<Assembly,string,bool,Type> typeResolver)
{
return GetType (typeName, assemblyResolver, typeResolver, false, false);
return rootElementType;
}
+ #region Enum methods
+
+ // Default implementations of GetEnumNames, GetEnumValues, and GetEnumUnderlyingType
+ // Subclass of types can override these methods.
+
+ public virtual string[] GetEnumNames()
+ {
+ if (!IsEnum)
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
+ Contract.Ensures(Contract.Result<String[]>() != null);
+
+ string[] names;
+ Array values;
+ GetEnumData(out names, out values);
+ return names;
+ }
+
+ // We don't support GetEnumValues in the default implementation because we cannot create an array of
+ // a non-runtime type. If there is strong need we can consider returning an object or int64 array.
+ public virtual Array GetEnumValues()
+ {
+ if (!IsEnum)
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
+ Contract.Ensures(Contract.Result<Array>() != null);
+
+ throw new NotImplementedException();
+ }
+
+ // Returns the enum values as an object array.
+ private Array GetEnumRawConstantValues()
+ {
+ string[] names;
+ Array values;
+ GetEnumData(out names, out values);
+ return values;
+ }
+
+ // This will return enumValues and enumNames sorted by the values.
+ private void GetEnumData(out string[] enumNames, out Array enumValues)
+ {
+ Contract.Ensures(Contract.ValueAtReturn<String[]>(out enumNames) != null);
+ Contract.Ensures(Contract.ValueAtReturn<Array>(out enumValues) != null);
+
+ FieldInfo[] flds = GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
+
+ object[] values = new object[flds.Length];
+ string[] names = new string[flds.Length];
+
+ for (int i = 0; i < flds.Length; i++)
+ {
+ names[i] = flds[i].Name;
+ values[i] = flds[i].GetRawConstantValue();
+ }
+
+ // Insertion Sort these values in ascending order.
+ // We use this O(n^2) algorithm, but it turns out that most of the time the elements are already in sorted order and
+ // the common case performance will be faster than quick sorting this.
+ IComparer comparer = Comparer.Default;
+ for (int i = 1; i < values.Length; i++)
+ {
+ int j = i;
+ string tempStr = names[i];
+ object val = values[i];
+ bool exchanged = false;
+
+ // Since the elements are sorted we only need to do one comparision, we keep the check for j inside the loop.
+ while (comparer.Compare(values[j - 1], val) > 0)
+ {
+ names[j] = names[j - 1];
+ values[j] = values[j - 1];
+ j--;
+ exchanged = true;
+ if (j == 0)
+ break;
+ }
+
+ if (exchanged)
+ {
+ names[j] = tempStr;
+ values[j] = val;
+ }
+ }
+
+ enumNames = names;
+ enumValues = values;
+ }
+
+ public virtual Type GetEnumUnderlyingType()
+ {
+ if (!IsEnum)
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
+ Contract.Ensures(Contract.Result<Type>() != null);
+
+ FieldInfo[] fields = GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+ if (fields == null || fields.Length != 1)
+ throw new ArgumentException(Environment.GetResourceString("Argument_InvalidEnum"), "enumType");
+
+ return fields[0].FieldType;
+ }
+
+ public virtual bool IsEnumDefined(object value)
+ {
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ if (!IsEnum)
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
+ Contract.EndContractBlock();
+
+ // Check if both of them are of the same type
+ Type valueType = value.GetType();
+
+ // If the value is an Enum then we need to extract the underlying value from it
+ if (valueType.IsEnum)
+ {
+ if (!valueType.IsEquivalentTo(this))
+ throw new ArgumentException(Environment.GetResourceString("Arg_EnumAndObjectMustBeSameType", valueType.ToString(), this.ToString()));
+
+ valueType = valueType.GetEnumUnderlyingType();
+ }
+
+ // If a string is passed in
+ if (valueType == typeof(string))
+ {
+ string[] names = GetEnumNames();
+ if (Array.IndexOf(names, value) >= 0)
+ return true;
+ else
+ return false;
+ }
+
+ // If an enum or integer value is passed in
+ if (Type.IsIntegerType(valueType))
+ {
+ Type underlyingType = GetEnumUnderlyingType();
+ // We cannot compare the types directly because valueType is always a runtime type but underlyingType might not be.
+ if (underlyingType.GetTypeCodeImpl() != valueType.GetTypeCodeImpl())
+ throw new ArgumentException(Environment.GetResourceString("Arg_EnumUnderlyingTypeAndObjectMustBeSameType", valueType.ToString(), underlyingType.ToString()));
+
+ Array values = GetEnumRawConstantValues();
+ return (BinarySearch(values, value) >= 0);
+ }
+ else if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
+ {
+ // if at this point the value type is not an integer type, then its type doesn't match the enum type
+ // NetCF used to throw an argument exception in this case
+ throw new ArgumentException(Environment.GetResourceString("Arg_EnumUnderlyingTypeAndObjectMustBeSameType", valueType.ToString(), GetEnumUnderlyingType()));
+ }
+ else
+ {
+ throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
+ }
+ }
+
+ public virtual string GetEnumName(object value)
+ {
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ if (!IsEnum)
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
+ Contract.EndContractBlock();
+
+ Type valueType = value.GetType();
+
+ if (!(valueType.IsEnum || Type.IsIntegerType(valueType)))
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
+
+ Array values = GetEnumRawConstantValues();
+ int index = BinarySearch(values, value);
+
+ if (index >= 0)
+ {
+ string[] names = GetEnumNames();
+ return names[index];
+ }
+
+ return null;
+ }
+
+ // Convert everything to ulong then perform a binary search.
+ private static int BinarySearch(Array array, object value)
+ {
+ ulong[] ulArray = new ulong[array.Length];
+ for (int i = 0; i < array.Length; ++i)
+ ulArray[i] = Enum.ToUInt64(array.GetValue(i));
+
+ ulong ulValue = Enum.ToUInt64(value);
+
+ return Array.BinarySearch(ulArray, ulValue);
+ }
+
+ internal static bool IsIntegerType(Type t)
+ {
+ return (t == typeof(int) ||
+ t == typeof(short) ||
+ t == typeof(ushort) ||
+ t == typeof(byte) ||
+ t == typeof(sbyte) ||
+ t == typeof(uint) ||
+ t == typeof(long) ||
+ t == typeof(ulong) ||
+ t == typeof(char) ||
+ t == typeof(bool));
+ }
+
+ #endregion
+
#if !MOBILE
void _Type.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
{