4cc6f3c55413ce9a421fbea0c27e5c62f4351a50
[mono.git] / mcs / class / corlib / System / Enum.cs
1 //
2 // System.Enum.cs
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Nick Drochak (ndrochak@gol.com)
7 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 //
9 // (C) Ximian, Inc.  http://www.ximian.com
10 //
11 //
12
13 //
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36 using System.Collections;
37 using System.Globalization;
38 using System.Runtime.CompilerServices;
39 using System.Runtime.InteropServices;
40
41 namespace System
42 {
43         internal struct MonoEnumInfo
44         {
45                 internal Type utype;
46                 internal Array values;
47                 internal string[] names;
48                 internal Hashtable name_hash;
49                 [ThreadStatic]
50                 static Hashtable cache;
51                 static Hashtable global_cache;
52                 static object global_cache_monitor;
53                 
54                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
55                 private static extern void get_enum_info (Type enumType, out MonoEnumInfo info);
56
57                 //
58                 // These comparers are needed because enumerations must be compared
59                 // using unsigned values so that negative numbers can be looked up
60                 // See bug: #371559
61                 //
62                 internal static SByteComparer  sbyte_comparer = new SByteComparer ();
63                 internal static ShortComparer short_comparer = new ShortComparer ();
64                 internal static IntComparer   int_comparer = new IntComparer ();
65                 internal static LongComparer  long_comparer = new LongComparer ();
66                 
67                 internal class SByteComparer : IComparer, System.Collections.Generic.IComparer<sbyte>
68                 {
69                         public int Compare (object x, object y)
70                         {
71                                 sbyte ix = (sbyte) x;
72                                 sbyte iy = (sbyte) y;
73                                 
74                                 return ((byte) ix) - ((byte) iy);
75                         }
76
77                         public int Compare (sbyte ix, sbyte iy)
78                         {
79                                 return ((byte) ix) - ((byte) iy);
80                         }
81                 }
82                 
83                 internal class ShortComparer : IComparer, System.Collections.Generic.IComparer<short>
84                 {
85                         public int Compare (object x, object y)
86                         {
87                                 short ix = (short) x;
88                                 short iy = (short) y;
89                                 
90                                 return ((ushort) ix) - ((ushort) iy);
91                         }
92
93                         public int Compare (short ix, short iy)
94                         {
95                                 return ((ushort) ix) - ((ushort) iy);
96                         }
97                 }
98                 
99                 internal class IntComparer : IComparer, System.Collections.Generic.IComparer<int>
100                   {
101                         public int Compare (object x, object y)
102                         {
103                                 int ix = (int) x;
104                                 int iy = (int) y;
105
106                                 if (ix == iy)
107                                         return 0;
108
109                                 if (((uint) ix) < ((uint) iy))
110                                         return -1;
111                                 return 1;
112                         }
113
114                         public int Compare (int ix, int iy)
115                         {
116                                 if (ix == iy)
117                                         return 0;
118
119                                 if (((uint) ix) < ((uint) iy))
120                                         return -1;
121                                 return 1;
122                         }
123                 }
124
125                 internal class LongComparer : IComparer, System.Collections.Generic.IComparer<long>
126                 {
127                         public int Compare (object x, object y)
128                         {
129                                 long ix = (long) x;
130                                 long iy = (long) y;
131                                 
132                                 if (ix == iy)
133                                         return 0;
134                                 if (((ulong) ix) < ((ulong) iy))
135                                         return -1;
136                                 return 1;
137                         }
138
139                         public int Compare (long ix, long iy)
140                         {
141                                 if (ix == iy)
142                                         return 0;
143                                 if (((ulong) ix) < ((ulong) iy))
144                                         return -1;
145                                 return 1;
146                         }
147                 }
148                         
149                 static MonoEnumInfo ()
150                 {
151                         global_cache_monitor = new object ();
152                         global_cache = new Hashtable ();
153                 }
154
155                 static Hashtable Cache {
156                         get {
157                                 if (cache == null) {
158                                         cache = new Hashtable ();
159                                 }
160                                 return cache;
161                         }
162                 }
163                 private MonoEnumInfo (MonoEnumInfo other)
164                 {
165                         utype = other.utype;
166                         values = other.values;
167                         names = other.names;
168                         name_hash = other.name_hash;
169                 }
170                 
171                 internal static void GetInfo (Type enumType, out MonoEnumInfo info)
172                 {
173                         /* First check the thread-local cache without locking */
174                         if (Cache.ContainsKey (enumType)) {
175                                 info = (MonoEnumInfo) cache [enumType];
176                                 return;
177                         }
178                         /* Threads could die, so keep a global cache too */
179                         lock (global_cache_monitor) {
180                                 if (global_cache.ContainsKey (enumType)) {
181                                         object boxedInfo = global_cache [enumType];
182                                         cache [enumType] = boxedInfo;
183                                         info = (MonoEnumInfo)boxedInfo;
184                                         return;
185                                 }
186                         }
187
188                         get_enum_info (enumType, out info);
189
190                         Type et = Enum.GetUnderlyingType (enumType);
191                         SortEnums (et, info.values, info.names);
192                         
193                         if (info.names.Length > 50) {
194                                 info.name_hash = new Hashtable (info.names.Length);
195                                 for (int i = 0; i <  info.names.Length; ++i)
196                                         info.name_hash [info.names [i]] = i;
197                         }
198                         MonoEnumInfo cached = new MonoEnumInfo (info);
199                         lock (global_cache_monitor) {
200                                 global_cache [enumType] = cached;
201                         }
202                 }
203                 
204                 internal static void SortEnums (Type et, Array values, Array names)
205                 {
206                         IComparer ic = null;
207                         if (et == typeof (int))
208                                 ic = int_comparer;
209                         else if (et == typeof (short))
210                                 ic = short_comparer;
211                         else if (et == typeof (sbyte))
212                                 ic = sbyte_comparer;
213                         else if (et == typeof (long))
214                                 ic = long_comparer;
215                         
216                         Array.Sort (values, names, ic);
217                 }
218         };
219
220         [Serializable]
221         [ComVisible (true)]
222         public abstract class Enum : ValueType, IComparable, IConvertible, IFormattable
223         {
224                 protected Enum ()
225                 {
226                 }
227
228                 // IConvertible methods Start -->
229                 public TypeCode GetTypeCode ()
230                 {
231                         return Type.GetTypeCode (GetUnderlyingType (this.GetType ()));
232                 }
233
234                 bool IConvertible.ToBoolean (IFormatProvider provider)
235                 {
236                         return Convert.ToBoolean (Value, provider);
237                 }
238
239                 byte IConvertible.ToByte (IFormatProvider provider)
240                 {
241                         return Convert.ToByte (Value, provider);
242                 }
243
244                 char IConvertible.ToChar (IFormatProvider provider)
245                 {
246                         return Convert.ToChar (Value, provider);
247                 }
248
249                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
250                 {
251                         return Convert.ToDateTime (Value, provider);
252                 }
253
254                 decimal IConvertible.ToDecimal (IFormatProvider provider)
255                 {       
256                         return Convert.ToDecimal (Value, provider);
257                 }
258
259                 double IConvertible.ToDouble (IFormatProvider provider)
260                 {       
261                         return Convert.ToDouble (Value, provider);
262                 }
263
264                 short IConvertible.ToInt16 (IFormatProvider provider)
265                 {
266                         return Convert.ToInt16 (Value, provider);
267                 }
268
269                 int IConvertible.ToInt32 (IFormatProvider provider)
270                 {
271                         return Convert.ToInt32 (Value, provider);
272                 }
273
274                 long IConvertible.ToInt64 (IFormatProvider provider)
275                 {
276                         return Convert.ToInt64 (Value, provider);
277                 }
278
279                 sbyte IConvertible.ToSByte (IFormatProvider provider)
280                 {
281                         return Convert.ToSByte (Value, provider);
282                 }
283
284                 float IConvertible.ToSingle (IFormatProvider provider)
285                 {
286                         return Convert.ToSingle (Value, provider);
287                 }
288
289                 object IConvertible.ToType (Type targetType, IFormatProvider provider)
290                 {
291                         if (targetType == null)
292                                 throw new ArgumentNullException ("targetType");
293                         if (targetType == typeof (string))
294                                 return ToString (provider);
295                         return Convert.ToType (Value, targetType, provider, false);
296                 }
297
298                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
299                 {
300                         return Convert.ToUInt16 (Value, provider);
301                 }
302
303                 uint IConvertible.ToUInt32 (IFormatProvider provider)
304                 {
305                         return Convert.ToUInt32 (Value, provider);
306                 }
307
308                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
309                 {
310                         return Convert.ToUInt64 (Value, provider);
311                 }
312
313                 // <-- End IConvertible methods
314
315                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
316                 private extern object get_value ();
317
318                 // wrap the icall into a property so we don't hav to use the icall everywhere
319                 private object Value {
320                         get { return get_value (); }
321                 }
322
323                 [ComVisible (true)]
324                 public static Array GetValues (Type enumType)
325                 {
326                         if (enumType == null)
327                                 throw new ArgumentNullException ("enumType");
328
329                         if (!enumType.IsEnum)
330                                 throw new ArgumentException ("enumType is not an Enum type.", "enumType");
331
332                         MonoEnumInfo info;
333                         MonoEnumInfo.GetInfo (enumType, out info);
334                         return (Array) info.values.Clone ();
335                 }
336
337                 [ComVisible (true)]
338                 public static string[] GetNames (Type enumType)
339                 {
340                         if (enumType == null)
341                                 throw new ArgumentNullException ("enumType");
342
343                         if (!enumType.IsEnum)
344                                 throw new ArgumentException ("enumType is not an Enum type.");
345
346                         MonoEnumInfo info;
347                         MonoEnumInfo.GetInfo (enumType, out info);
348                         return (string []) info.names.Clone ();
349                 }
350
351                 //
352                 // The faster, non-boxing version.   It must use the special MonoEnumInfo.xxx_comparers
353                 // to ensure that we are perfoming bitwise compares, and not signed compares.
354                 //
355                 // It also tries to use the non-boxing version of the various Array.BinarySearch methods
356                 //
357                 static int FindPosition (Type enumType, object value, Array values)
358                 {
359                         switch (Type.GetTypeCode (GetUnderlyingType (enumType))) {
360                         case TypeCode.SByte:
361                                 sbyte [] sbyte_array = values as sbyte [];
362                                 return Array.BinarySearch (sbyte_array, (sbyte) value,  MonoEnumInfo.sbyte_comparer);
363
364                         case TypeCode.Byte:
365                                 byte [] byte_array = values as byte [];
366                                 return Array.BinarySearch (byte_array, (byte) value);
367
368                         case TypeCode.Int16:
369                                 short [] short_array = values as short [];
370                                 return Array.BinarySearch (short_array, (short)value, MonoEnumInfo.short_comparer);
371
372                         case TypeCode.UInt16:
373                                 ushort [] ushort_array = values as ushort [];
374                                 return Array.BinarySearch (ushort_array, (ushort)value);
375                 
376                         case TypeCode.Int32:
377                                 int[] int_array = values as int[];
378                                 return Array.BinarySearch (int_array, (int)value, MonoEnumInfo.int_comparer);
379
380                         case TypeCode.UInt32:
381                                 uint[] uint_array = values as uint [];
382                                 return Array.BinarySearch (uint_array, (uint)value);                    
383                         
384                         case TypeCode.Int64:
385                                 long [] long_array = values as long [];
386                                 return Array.BinarySearch (long_array, (long) value,  MonoEnumInfo.long_comparer);
387
388                         case TypeCode.UInt64:
389                                 ulong [] ulong_array = values as ulong [];
390                                 return Array.BinarySearch (ulong_array, (ulong) value);
391
392                         default:
393                                 // This should never happen
394                                 return Array.BinarySearch (values, value);
395                         }
396                 }
397         
398                 [ComVisible (true)]
399                 public static string GetName (Type enumType, object value)
400                 {
401                         if (enumType == null)
402                                 throw new ArgumentNullException ("enumType");
403                         if (value == null)
404                                 throw new ArgumentNullException ("value");
405
406                         if (!enumType.IsEnum)
407                                 throw new ArgumentException ("enumType is not an Enum type.", "enumType");
408
409                         MonoEnumInfo info;
410                         value = ToObject (enumType, value);
411                         MonoEnumInfo.GetInfo (enumType, out info);
412
413                         int i = FindPosition (enumType, value, info.values);
414                         return (i >= 0) ? info.names [i] : null;
415                 }
416
417                 [ComVisible (true)]
418                 public static bool IsDefined (Type enumType, object value)
419                 {
420                         if (enumType == null)
421                                 throw new ArgumentNullException ("enumType");
422                         if (value == null)
423                                 throw new ArgumentNullException ("value");
424
425                         if (!enumType.IsEnum)
426                                 throw new ArgumentException ("enumType is not an Enum type.", "enumType");
427
428                         MonoEnumInfo info;
429                         MonoEnumInfo.GetInfo (enumType, out info);
430
431                         Type vType = value.GetType ();
432                         if (vType == typeof(String)) {
433                                 return ((IList)(info.names)).Contains (value);
434                         } else if ((vType == info.utype) || (vType == enumType)) {
435                                 value = ToObject (enumType, value);
436                                 MonoEnumInfo.GetInfo (enumType, out info);
437
438                                 return FindPosition (enumType, value, info.values) >= 0;
439                         } else {
440                                 throw new ArgumentException("The value parameter is not the correct type. "
441                                         + "It must be type String or the same type as the underlying type "
442                                         + "of the Enum.");
443                         }
444                 }
445
446                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
447                 private static extern Type get_underlying_type (Type enumType);
448
449                 [ComVisible (true)]
450                 public static Type GetUnderlyingType (Type enumType)
451                 {
452                         if (enumType == null)
453                                 throw new ArgumentNullException ("enumType");
454
455                         if (!enumType.IsEnum)
456                                 throw new ArgumentException ("enumType is not an Enum type.", "enumType");
457
458                         return get_underlying_type (enumType);
459                 }
460
461                 [ComVisible (true)]
462                 public static object Parse (Type enumType, string value)
463                 {
464                         // Note: Parameters are checked in the other overload
465                         return Parse (enumType, value, false);
466                 }
467
468                 private static int FindName (Hashtable name_hash, string [] names, string name,  bool ignoreCase)
469                 {
470                         if (!ignoreCase) {
471                                 /* For enums with many values, use a hash table */
472                                 if (name_hash != null) {
473                                         object val = name_hash [name];
474                                         if (val != null)
475                                                 return (int)val;
476                                 } else {
477                                         for (int i = 0; i < names.Length; ++i) {
478                                                 if (name == names [i])
479                                                         return i;
480                                         }
481                                 }
482                         } else {
483                                 for (int i = 0; i < names.Length; ++i) {
484                                         if (String.Compare (name, names [i], ignoreCase, CultureInfo.InvariantCulture) == 0)
485                                                 return i;
486                                 }
487                         }
488                         return -1;
489                 }
490
491                 // Helper function for dealing with [Flags]-style enums.
492                 private static ulong GetValue (object value, TypeCode typeCode)
493                 {
494                         switch (typeCode) {
495                         case TypeCode.Byte:
496                                 return (byte) value;
497                         case TypeCode.SByte:
498                                 return (byte) ((sbyte) value);
499                         case TypeCode.Int16:
500                                 return (ushort) ((short) value);
501                         case TypeCode.Int32:
502                                 return (uint) ((int) value);
503                         case TypeCode.Int64:
504                                 return (ulong) ((long) value);
505                         case TypeCode.UInt16:
506                                 return (ushort) value;
507                         case TypeCode.UInt32:
508                                 return (uint) value;
509                         case TypeCode.UInt64:
510                                 return (ulong) value;
511                         }
512                         throw new ArgumentException ("typeCode is not a valid type code for an Enum");
513                 }
514
515                 private static char [] split_char = { ',' };
516
517                 [ComVisible(true)]
518                 public static object Parse (Type enumType, string value, bool ignoreCase)
519                 {
520                         if (enumType == null)
521                                 throw new ArgumentNullException ("enumType");
522
523                         if (value == null)
524                                 throw new ArgumentNullException ("value");
525
526                         if (!enumType.IsEnum)
527                                 throw new ArgumentException ("enumType is not an Enum type.", "enumType");
528
529                         value = value.Trim ();
530                         if (value.Length == 0)
531                                 throw new ArgumentException ("An empty string is not considered a valid value.");
532
533                         object result;
534                         if (!Parse (enumType, value, ignoreCase, out result))
535                                 throw new ArgumentException (String.Format ("The requested value '{0}' was not found.", value));
536
537                         return result;
538                 }
539
540                 static bool Parse<TEnum> (Type enumType, string value, bool ignoreCase, out TEnum result)
541                 {
542                         result = default (TEnum);
543
544                         MonoEnumInfo info;
545                         MonoEnumInfo.GetInfo (enumType, out info);
546
547                         // is 'value' a named constant?
548                         int loc = FindName (info.name_hash, info.names, value, ignoreCase);
549                         if (loc >= 0) {
550                                 result = (TEnum) info.values.GetValue (loc);
551                                 return true;
552                         }
553
554                         TypeCode typeCode = ((Enum) info.values.GetValue (0)).GetTypeCode ();
555
556                         // is 'value' a list of named constants?
557                         if (value.IndexOf (',') != -1) {
558                                 string [] names = value.Split (split_char);
559                                 ulong retVal = 0;
560                                 for (int i = 0; i < names.Length; ++i) {
561                                         loc = FindName (info.name_hash, info.names, names [i].Trim (), ignoreCase);
562                                         if (loc < 0)
563                                                 return false;
564
565                                         retVal |= GetValue (info.values.GetValue (loc), typeCode);
566                                 }
567                                 result = (TEnum) ToObject (enumType, retVal);
568                                 return true;
569                         }
570
571                         // is 'value' a number?
572                         switch (typeCode) {
573                         case TypeCode.SByte:
574                                 sbyte sb;
575                                 if (!SByte.TryParse (value, out sb))
576                                         return false;
577                                 result = (TEnum) ToObject (enumType, sb);
578                                 break;
579                         case TypeCode.Byte:
580                                 byte b;
581                                 if (!Byte.TryParse (value, out b))
582                                         return false;
583                                 result = (TEnum) ToObject (enumType, b);
584                                 break;
585                         case TypeCode.Int16:
586                                 short i16;
587                                 if (!Int16.TryParse (value, out i16))
588                                         return false;
589                                 result = (TEnum) ToObject (enumType, i16);
590                                 break;
591                         case TypeCode.UInt16:
592                                 ushort u16;
593                                 if (!UInt16.TryParse (value, out u16))
594                                         return false;
595                                 result = (TEnum) ToObject (enumType, u16);
596                                 break;
597                         case TypeCode.Int32:
598                                 int i32;
599                                 if (!Int32.TryParse (value, out i32))
600                                         return false;
601                                 result = (TEnum) ToObject (enumType, i32);
602                                 break;
603                         case TypeCode.UInt32:
604                                 uint u32;
605                                 if (!UInt32.TryParse (value, out u32))
606                                         return false;
607                                 result = (TEnum) ToObject (enumType, u32);
608                                 break;
609                         case TypeCode.Int64:
610                                 long i64;
611                                 if (!Int64.TryParse (value, out i64))
612                                         return false;
613                                 result = (TEnum) ToObject (enumType, i64);
614                                 break;
615                         case TypeCode.UInt64:
616                                 ulong u64;
617                                 if (!UInt64.TryParse (value, out u64))
618                                         return false;
619                                 result = (TEnum) ToObject (enumType, u64);
620                                 break;
621                         default:
622                                 break;
623                         }
624
625                         return true;
626                 }
627
628 #if NET_4_0 || MOONLIGHT || MOBILE
629                 public static bool TryParse<TEnum> (string value, out TEnum result) where TEnum : struct
630                 {
631                         return TryParse (value, false, out result);
632                 }
633
634                 public static bool TryParse<TEnum> (string value, bool ignoreCase, out TEnum result) where TEnum : struct
635                 {
636                         Type tenum_type = typeof (TEnum);
637                         if (!tenum_type.IsEnum)
638                                 throw new ArgumentException("TEnum is not an Enum type.", "enumType");
639
640                         result = default (TEnum);
641
642                         if (value == null || value.Trim ().Length == 0)
643                                 return false;
644
645                         return Parse (tenum_type, value, ignoreCase, out result);
646                 }
647 #endif
648
649                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
650                 private extern int compare_value_to (object other);
651
652                 /// <summary>
653                 ///   Compares the enum value with another enum value of the same type.
654                 /// </summary>
655                 ///
656                 /// <remarks/>
657                 public int CompareTo (object target)
658                 {
659                         Type thisType;
660
661                         if (target == null)
662                                 return 1;
663
664                         thisType = this.GetType ();
665                         if (target.GetType() != thisType) {
666                                 throw new ArgumentException (String.Format (
667                                         "Object must be the same type as the enum. The type passed in was {0}; the enum type was {1}.", 
668                                         target.GetType(), thisType));
669                         }
670
671                         return compare_value_to (target);
672                 }
673
674                 public override string ToString ()
675                 {
676                         return ToString ("G");
677                 }
678
679                 [Obsolete("Provider is ignored, just use ToString")]
680                 public string ToString (IFormatProvider provider)
681                 {
682                         return ToString ("G", provider);
683                 }
684
685                 public string ToString (String format)
686                 {
687                         if (format == String.Empty || format == null)
688                                 format = "G";
689                         
690                         return Format (this.GetType (), this.Value, format);
691                 }
692
693                 [Obsolete("Provider is ignored, just use ToString")]
694                 public string ToString (String format, IFormatProvider provider)
695                 {
696                         // provider is not used for Enums
697
698                         if (format == String.Empty || format == null) {
699                                 format = "G";
700                         }
701                         return Format (this.GetType(), this.Value, format);
702                 }
703
704                 [ComVisible (true)]
705                 public static object ToObject (Type enumType, byte value)
706                 {
707                         return ToObject (enumType, (object)value);
708                 }
709
710                 [ComVisible (true)]
711                 public static object ToObject (Type enumType, short value)
712                 {
713                         return ToObject (enumType, (object)value);
714                 }
715
716                 [ComVisible (true)]
717                 public static object ToObject (Type enumType, int value)
718                 {
719                         return ToObject (enumType, (object)value);
720                 }
721
722                 [ComVisible (true)]
723                 public static object ToObject (Type enumType, long value)
724                 {
725                         return ToObject (enumType, (object)value);
726                 }
727
728                 [ComVisible (true)]
729                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
730                 public static extern object ToObject (Type enumType, object value);
731
732                 [ComVisible (true)]
733                 [CLSCompliant (false)]
734                 public static object ToObject (Type enumType, sbyte value)
735                 {
736                         return ToObject (enumType, (object)value);
737                 }
738
739                 [ComVisible (true)]
740                 [CLSCompliant (false)]
741                 public static object ToObject (Type enumType, ushort value)
742                 {
743                         return ToObject (enumType, (object)value);
744                 }
745
746                 [ComVisible (true)]
747                 [CLSCompliant (false)]
748                 public static object ToObject (Type enumType, uint value)
749                 {
750                         return ToObject (enumType, (object)value);
751                 }
752
753                 [ComVisible (true)]
754                 [CLSCompliant (false)]
755                 public static object ToObject (Type enumType, ulong value)
756                 {
757                         return ToObject (enumType, (object)value);
758                 }
759
760                 public override bool Equals (object obj)
761                 {
762                         return DefaultEquals (this, obj);
763                 }
764
765                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
766                 private extern int get_hashcode ();
767
768                 public override int GetHashCode ()
769                 {
770                         return get_hashcode ();
771                 }
772
773                 private static string FormatSpecifier_X (Type enumType, object value, bool upper)
774                 {
775                         switch (Type.GetTypeCode (enumType)) {
776                                 case TypeCode.SByte:
777                                         return ((sbyte)value).ToString (upper ? "X2" : "x2");
778                                 case TypeCode.Byte:
779                                         return ((byte)value).ToString (upper ? "X2" : "x2");
780                                 case TypeCode.Int16:
781                                         return ((short)value).ToString (upper ? "X4" : "x4");
782                                 case TypeCode.UInt16:
783                                         return ((ushort)value).ToString (upper ? "X4" : "x4");
784                                 case TypeCode.Int32:
785                                         return ((int)value).ToString (upper ? "X8" : "x8");
786                                 case TypeCode.UInt32:
787                                         return ((uint)value).ToString (upper ? "X8" : "x8");
788                                 case TypeCode.Int64:
789                                         return ((long)value).ToString (upper ? "X16" : "x16");
790                                 case TypeCode.UInt64:
791                                         return ((ulong)value).ToString (upper ? "X16" : "x16");
792                                 default:
793                                         throw new Exception ("Invalid type code for enumeration.");
794                         }
795                 }
796
797                 static string FormatFlags (Type enumType, object value)
798                 {
799                         string retVal = String.Empty;
800                         MonoEnumInfo info;
801                         MonoEnumInfo.GetInfo (enumType, out info);
802                         string asString = value.ToString ();
803                         if (asString == "0") {
804                                 retVal = GetName (enumType, value);
805                                 if (retVal == null)
806                                         retVal = asString;
807                                 return retVal;
808                         }
809                         // This is ugly, yes.  We need to handle the different integer
810                         // types for enums.  If someone else has a better idea, be my guest.
811                         switch (((Enum)info.values.GetValue (0)).GetTypeCode ()) {
812                         case TypeCode.SByte: {
813                                 sbyte flags = (sbyte) value;
814                                 sbyte enumValue;
815                                 for (int i = info.values.Length - 1; i >= 0; i--) {
816                                         enumValue = (sbyte) info.values.GetValue (i);
817                                         if (enumValue == 0)
818                                                 continue;
819
820                                         if ((flags & enumValue) == enumValue) {
821                                                 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
822                                                 flags -= enumValue;
823                                         }
824                                 }
825                                 if (flags != 0) return asString;
826                                 }
827                                 break;
828                         case TypeCode.Byte: {
829                                 byte flags = (byte) value;
830                                 byte enumValue;
831                                 for (int i = info.values.Length - 1; i >= 0; i--) {
832                                         enumValue = (byte) info.values.GetValue (i);
833                                         if (enumValue == 0)
834                                                 continue;
835
836                                         if ((flags & enumValue) == enumValue) {
837                                                 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
838                                                 flags -= enumValue;
839                                         }
840                                 }
841                                 if (flags != 0) return asString;
842                                 }
843                                 break;
844                         case TypeCode.Int16: {
845                                 short flags = (short) value;
846                                 short enumValue;
847                                 for (int i = info.values.Length - 1; i >= 0; i--) {
848                                         enumValue = (short) info.values.GetValue (i);
849                                         if (enumValue == 0)
850                                                 continue;
851
852                                         if ((flags & enumValue) == enumValue) {
853                                                 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
854                                                 flags -= enumValue;
855                                         }
856                                 }
857                                 if (flags != 0) return asString;
858                                 }
859                                 break;
860                         case TypeCode.Int32: {
861                                 int flags = (int) value;
862                                 int enumValue;
863                                 for (int i = info.values.Length - 1; i >= 0; i--) {
864                                         enumValue = (int) info.values.GetValue (i);
865                                         if (enumValue == 0)
866                                                 continue;
867
868                                         if ((flags & enumValue) == enumValue) {
869                                                 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
870                                                 flags -= enumValue;
871                                         }
872                                 }
873                                 if (flags != 0) return asString;
874                                 }
875                                 break;
876                         case TypeCode.UInt16: {
877                                 ushort flags = (ushort) value;
878                                 ushort enumValue;
879                                 for (int i = info.values.Length - 1; i >= 0; i--) {
880                                         enumValue = (ushort) info.values.GetValue (i);
881                                         if (enumValue == 0)
882                                                 continue;
883
884                                         if ((flags & enumValue) == enumValue) {
885                                                 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
886                                                 flags -= enumValue;
887                                         }
888                                 }
889                                 if (flags != 0) return asString;
890                                 }
891                                 break;
892                         case TypeCode.UInt32: {
893                                 uint flags = (uint) value;
894                                 uint enumValue;
895                                 for (int i = info.values.Length - 1; i >= 0; i--) {
896                                         enumValue = (uint) info.values.GetValue (i);
897                                         if (enumValue == 0)
898                                                 continue;
899
900                                         if ((flags & enumValue) == enumValue) {
901                                                 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
902                                                 flags -= enumValue;
903                                         }
904                                 }
905                                 if (flags != 0) return asString;
906                                 }
907                                 break;
908                         case TypeCode.Int64: {
909                                 long flags = (long) value;
910                                 long enumValue;
911                                 for (int i = info.values.Length - 1; i >= 0; i--) {
912                                         enumValue = (long) info.values.GetValue (i);
913                                         if (enumValue == 0)
914                                                 continue;
915
916                                         if ((flags & enumValue) == enumValue) {
917                                                 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
918                                                 flags -= enumValue;
919                                         }
920                                 }
921                                 if (flags != 0) return asString;
922                                 }
923                                 break;
924                         case TypeCode.UInt64: {
925                                 ulong flags = (ulong) value;
926                                 ulong enumValue;
927                                 for (int i = info.values.Length - 1; i >= 0; i--) {
928                                         enumValue = (ulong) info.values.GetValue (i);
929                                         if (enumValue == 0)
930                                                 continue;
931
932                                         if ((flags & enumValue) == enumValue) {
933                                                 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
934                                                 flags -= enumValue;
935                                         }
936                                 }
937                                 if (flags != 0) return asString;
938                                 }
939                                 break;
940                         }
941
942                         if (retVal == String.Empty)
943                                 return asString;
944
945                         return retVal;
946                 }
947
948                 [ComVisible (true)]
949                 public static string Format (Type enumType, object value, string format)
950                 {
951                         if (enumType == null)
952                                 throw new ArgumentNullException ("enumType");
953                         if (value == null)
954                                 throw new ArgumentNullException ("value");
955                         if (format == null)
956                                 throw new ArgumentNullException ("format");
957
958                         if (!enumType.IsEnum)
959                                 throw new ArgumentException ("enumType is not an Enum type.", "enumType");
960                         
961                         Type vType = value.GetType();
962                         Type underlyingType = Enum.GetUnderlyingType (enumType);
963                         if (vType.IsEnum) {
964                                 if (vType != enumType)
965                                         throw new ArgumentException (string.Format(CultureInfo.InvariantCulture,
966                                                 "Object must be the same type as the enum. The type" +
967                                                 " passed in was {0}; the enum type was {1}.",
968                                                 vType.FullName, enumType.FullName));
969                         } else if (vType != underlyingType) {
970                                 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
971                                         "Enum underlying type and the object must be the same type" +
972                                         " or object. Type passed in was {0}; the enum underlying" +
973                                         " type was {1}.", vType.FullName, underlyingType.FullName));
974                         }
975
976                         if (format.Length != 1)
977                                 throw new FormatException ("Format String can be only \"G\",\"g\",\"X\"," + 
978                                         "\"x\",\"F\",\"f\",\"D\" or \"d\".");
979
980                         char formatChar = format [0];
981                         string retVal;
982                         if ((formatChar == 'G' || formatChar == 'g')) {
983                                 if (!enumType.IsDefined (typeof(FlagsAttribute), false)) {
984                                         retVal = GetName (enumType, value);
985                                         if (retVal == null)
986                                                 retVal = value.ToString();
987
988                                         return retVal;
989                                 }
990
991                                 formatChar = 'f';
992                         }
993                         
994                         if ((formatChar == 'f' || formatChar == 'F'))
995                                 return FormatFlags (enumType, value);
996
997                         retVal = String.Empty;
998                         switch (formatChar) {
999                         case 'X':
1000                                 retVal = FormatSpecifier_X (enumType, value, true);
1001                                 break;
1002                         case 'x':
1003                                 retVal = FormatSpecifier_X (enumType, value, false);
1004                                 break;
1005                         case 'D':
1006                         case 'd':
1007                                 if (underlyingType == typeof (ulong)) {
1008                                         ulong ulongValue = Convert.ToUInt64 (value);
1009                                         retVal = ulongValue.ToString ();
1010                                 } else {
1011                                         long longValue = Convert.ToInt64 (value);
1012                                         retVal = longValue.ToString ();
1013                                 }
1014                                 break;
1015                         default:
1016                                 throw new FormatException ("Format String can be only \"G\",\"g\",\"X\"," + 
1017                                         "\"x\",\"F\",\"f\",\"D\" or \"d\".");
1018                         }
1019                         return retVal;
1020                 }
1021 #if NET_4_0 || MOONLIGHT || MOBILE
1022                 public bool HasFlag (Enum flag)
1023                 {
1024                         var val = get_value ();
1025                         ulong mvalue = GetValue (val, Type.GetTypeCode (val.GetType ()));
1026                         ulong fvalue = GetValue (flag, Type.GetTypeCode (flag.GetType ()));
1027
1028                         return ((mvalue & fvalue) == fvalue);
1029                 }
1030 #endif
1031         }
1032 }